From dde0756bed9702c95c918af247e9339bc913bb48 Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Tue, 24 May 2022 10:23:44 -0400 Subject: [PATCH 001/430] add accuracy challenge mod --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 1 + osu.Game.Rulesets.Mania/ManiaRuleset.cs | 1 + osu.Game.Rulesets.Osu/OsuRuleset.cs | 3 +- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 1 + .../Rulesets/Mods/ModAccuracyChallenge.cs | 59 +++++++++++++++++++ .../Rulesets/Mods/ModEasyWithExtraLives.cs | 3 + osu.Game/Rulesets/Mods/ModPerfect.cs | 2 +- 7 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index 80b9436b2c..bcce28adb2 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -109,6 +109,7 @@ namespace osu.Game.Rulesets.Catch new MultiMod(new CatchModDoubleTime(), new CatchModNightcore()), new CatchModHidden(), new CatchModFlashlight(), + //new ModAccuracyChallenge(), }; case ModType.Conversion: diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index bd6a67bf67..8f2d679750 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -222,6 +222,7 @@ namespace osu.Game.Rulesets.Mania new MultiMod(new ManiaModDoubleTime(), new ManiaModNightcore()), new MultiMod(new ManiaModFadeIn(), new ManiaModHidden()), new ManiaModFlashlight(), + //new ModAccuracyChallenge(), }; case ModType.Conversion: diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 207e7a4ab0..15998a48c3 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -159,7 +159,8 @@ namespace osu.Game.Rulesets.Osu new MultiMod(new OsuModDoubleTime(), new OsuModNightcore()), new OsuModHidden(), new MultiMod(new OsuModFlashlight(), new OsuModBlinds()), - new OsuModStrictTracking() + new OsuModStrictTracking(), + new ModAccuracyChallenge(), }; case ModType.Conversion: diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 615fbf093f..655aba88e3 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -128,6 +128,7 @@ namespace osu.Game.Rulesets.Taiko new MultiMod(new TaikoModDoubleTime(), new TaikoModNightcore()), new TaikoModHidden(), new TaikoModFlashlight(), + //new ModAccuracyChallenge(), }; case ModType.Conversion: diff --git a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs new file mode 100644 index 0000000000..bb7d3896b2 --- /dev/null +++ b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs @@ -0,0 +1,59 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Linq; +using osu.Framework.Bindables; +using osu.Framework.Graphics.Sprites; +using osu.Game.Configuration; +using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays.Settings; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.Judgements; + +namespace osu.Game.Rulesets.Mods +{ + public class ModAccuracyChallenge : ModFailCondition + { + public override string Name => "Accuracy Challenge"; + public override string Acronym => "AC"; + public override string Description => "Fail the map if you don't maintain a certain accuracy."; + public override IconUsage? Icon => FontAwesome.Solid.Calculator; + public override ModType Type => ModType.DifficultyIncrease; + public override double ScoreMultiplier => 1.0; + public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModEasyWithExtraLives)).Append(typeof(ModPerfect)).ToArray(); + + [SettingSource("Minimum accuracy", "Trigger a failure if your accuracy goes below this value.", SettingControlType = typeof(SettingsSlider))] + public BindableNumber MinimumAccuracy { get; } = new BindableDouble + { + MinValue = 0, + MaxValue = 1, + Precision = 0.01, + Default = 0.9, + Value = 0.9, + }; + + private double baseScore; + private double maxBaseScore; + private double accuracy => maxBaseScore > 0 ? baseScore / maxBaseScore : 1; + + protected override bool FailCondition(HealthProcessor healthProcessor, JudgementResult result) + { + if (!result.Type.IsScorable() || result.Type.IsBonus()) + return false; + + baseScore += result.Type.IsHit() ? result.Judgement.NumericResultFor(result) : 0; + maxBaseScore += result.Judgement.MaxNumericResult; + + return accuracy < MinimumAccuracy.Value; + } + } + + public class PercentSlider : OsuSliderBar + { + public PercentSlider() + { + DisplayAsPercentage = true; + } + } +} diff --git a/osu.Game/Rulesets/Mods/ModEasyWithExtraLives.cs b/osu.Game/Rulesets/Mods/ModEasyWithExtraLives.cs index 2ac0f59d84..7e6b085f8a 100644 --- a/osu.Game/Rulesets/Mods/ModEasyWithExtraLives.cs +++ b/osu.Game/Rulesets/Mods/ModEasyWithExtraLives.cs @@ -1,6 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; +using System.Linq; using Humanizer; using osu.Framework.Bindables; using osu.Game.Beatmaps; @@ -19,6 +21,7 @@ namespace osu.Game.Rulesets.Mods }; public override string SettingDescription => Retries.IsDefault ? string.Empty : $"{"lives".ToQuantity(Retries.Value)}"; + public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModAccuracyChallenge)).ToArray(); private int retries; diff --git a/osu.Game/Rulesets/Mods/ModPerfect.cs b/osu.Game/Rulesets/Mods/ModPerfect.cs index 9016a24f8d..4c68d0d375 100644 --- a/osu.Game/Rulesets/Mods/ModPerfect.cs +++ b/osu.Game/Rulesets/Mods/ModPerfect.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Mods public override double ScoreMultiplier => 1; public override string Description => "SS or quit."; - public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModSuddenDeath)).ToArray(); + public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModSuddenDeath)).Append(typeof(ModAccuracyChallenge)).ToArray(); protected ModPerfect() { From 252bacc8d4aeee7bacf96598b97a28eef7e884c7 Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Tue, 24 May 2022 10:56:31 -0400 Subject: [PATCH 002/430] revert more testing leftovers... --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 2 +- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 2 +- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index bcce28adb2..9ddafc9315 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -109,7 +109,7 @@ namespace osu.Game.Rulesets.Catch new MultiMod(new CatchModDoubleTime(), new CatchModNightcore()), new CatchModHidden(), new CatchModFlashlight(), - //new ModAccuracyChallenge(), + new ModAccuracyChallenge(), }; case ModType.Conversion: diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 8f2d679750..659d7f242f 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -222,7 +222,7 @@ namespace osu.Game.Rulesets.Mania new MultiMod(new ManiaModDoubleTime(), new ManiaModNightcore()), new MultiMod(new ManiaModFadeIn(), new ManiaModHidden()), new ManiaModFlashlight(), - //new ModAccuracyChallenge(), + new ModAccuracyChallenge(), }; case ModType.Conversion: diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 655aba88e3..a80c87ecd3 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -128,7 +128,7 @@ namespace osu.Game.Rulesets.Taiko new MultiMod(new TaikoModDoubleTime(), new TaikoModNightcore()), new TaikoModHidden(), new TaikoModFlashlight(), - //new ModAccuracyChallenge(), + new ModAccuracyChallenge(), }; case ModType.Conversion: From 5944a15c30abfa9dfc56b169d68955f68bd0edbb Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Tue, 24 May 2022 20:04:57 -0400 Subject: [PATCH 003/430] review pass eins --- osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs | 5 +++-- osu.Game/Rulesets/Mods/ModPerfect.cs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs index bb7d3896b2..804ce867af 100644 --- a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs +++ b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs @@ -21,12 +21,13 @@ namespace osu.Game.Rulesets.Mods public override IconUsage? Icon => FontAwesome.Solid.Calculator; public override ModType Type => ModType.DifficultyIncrease; public override double ScoreMultiplier => 1.0; - public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModEasyWithExtraLives)).Append(typeof(ModPerfect)).ToArray(); + public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(ModEasyWithExtraLives), typeof(ModPerfect) }).ToArray(); + public override bool RequiresConfiguration => false; [SettingSource("Minimum accuracy", "Trigger a failure if your accuracy goes below this value.", SettingControlType = typeof(SettingsSlider))] public BindableNumber MinimumAccuracy { get; } = new BindableDouble { - MinValue = 0, + MinValue = 0.01, MaxValue = 1, Precision = 0.01, Default = 0.9, diff --git a/osu.Game/Rulesets/Mods/ModPerfect.cs b/osu.Game/Rulesets/Mods/ModPerfect.cs index 4c68d0d375..c40c651655 100644 --- a/osu.Game/Rulesets/Mods/ModPerfect.cs +++ b/osu.Game/Rulesets/Mods/ModPerfect.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Mods public override double ScoreMultiplier => 1; public override string Description => "SS or quit."; - public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModSuddenDeath)).Append(typeof(ModAccuracyChallenge)).ToArray(); + public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(ModSuddenDeath), typeof(ModAccuracyChallenge) }).ToArray(); protected ModPerfect() { From 58d4aeb4fb1b60fe5c5fe7e701fc5db469e1ad8e Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Wed, 25 May 2022 15:11:06 -0400 Subject: [PATCH 004/430] add accuracy calculation comment --- osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs index 804ce867af..fe12b72d1e 100644 --- a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs +++ b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs @@ -40,6 +40,7 @@ namespace osu.Game.Rulesets.Mods protected override bool FailCondition(HealthProcessor healthProcessor, JudgementResult result) { + // accuracy calculation logic taken from `ScoreProcessor`. should be updated here if the formula ever changes. if (!result.Type.IsScorable() || result.Type.IsBonus()) return false; From 6710df94a79052689d67b79c3ec55dfd81fd7107 Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Mon, 6 Jun 2022 12:05:45 -0400 Subject: [PATCH 005/430] change max accuracy to 99% --- osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs index fe12b72d1e..307a9594fe 100644 --- a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs +++ b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs @@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Mods public BindableNumber MinimumAccuracy { get; } = new BindableDouble { MinValue = 0.01, - MaxValue = 1, + MaxValue = 0.99, Precision = 0.01, Default = 0.9, Value = 0.9, From fdbec4f8c0c8082445beaef065c7df9aa4a36065 Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Wed, 8 Jun 2022 23:44:34 -0400 Subject: [PATCH 006/430] display tooltip accuracy as percentage --- osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs index 307a9594fe..2c088e880b 100644 --- a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs +++ b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs @@ -23,6 +23,7 @@ namespace osu.Game.Rulesets.Mods public override double ScoreMultiplier => 1.0; public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(ModEasyWithExtraLives), typeof(ModPerfect) }).ToArray(); public override bool RequiresConfiguration => false; + public override string SettingDescription => base.SettingDescription.Replace(MinimumAccuracy.Value.ToString(), MinimumAccuracy.Value.ToString("##%")); [SettingSource("Minimum accuracy", "Trigger a failure if your accuracy goes below this value.", SettingControlType = typeof(SettingsSlider))] public BindableNumber MinimumAccuracy { get; } = new BindableDouble From 99dc2fbc3e51a4d8a81eba6c595eeda7079532a9 Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Thu, 9 Jun 2022 00:15:15 -0400 Subject: [PATCH 007/430] specify culture --- osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs index 2c088e880b..891832a353 100644 --- a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs +++ b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Globalization; using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; @@ -23,7 +24,7 @@ namespace osu.Game.Rulesets.Mods public override double ScoreMultiplier => 1.0; public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(ModEasyWithExtraLives), typeof(ModPerfect) }).ToArray(); public override bool RequiresConfiguration => false; - public override string SettingDescription => base.SettingDescription.Replace(MinimumAccuracy.Value.ToString(), MinimumAccuracy.Value.ToString("##%")); + 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))] public BindableNumber MinimumAccuracy { get; } = new BindableDouble From 4b73c423bda6c0c8d14b0db3d046c8cd8820fb9f Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Thu, 9 Jun 2022 18:58:22 -0400 Subject: [PATCH 008/430] don't specify icon --- osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs index 891832a353..74a9a205a0 100644 --- a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs +++ b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs @@ -5,7 +5,6 @@ using System; using System.Globalization; using System.Linq; using osu.Framework.Bindables; -using osu.Framework.Graphics.Sprites; using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Settings; @@ -19,7 +18,6 @@ namespace osu.Game.Rulesets.Mods public override string Name => "Accuracy Challenge"; public override string Acronym => "AC"; public override string Description => "Fail the map if you don't maintain a certain accuracy."; - public override IconUsage? Icon => FontAwesome.Solid.Calculator; public override ModType Type => ModType.DifficultyIncrease; public override double ScoreMultiplier => 1.0; public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(ModEasyWithExtraLives), typeof(ModPerfect) }).ToArray(); From 18b4317e99921e133aed5549a00e0b31445a63cf Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 1 Dec 2022 11:57:50 +0100 Subject: [PATCH 009/430] 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 010/430] 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 011/430] 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 012/430] 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 013/430] 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 014/430] 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 015/430] 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 016/430] 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 0db6c2ada147b5749228d414ff8521e83b69bf96 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 3 Dec 2022 22:38:11 +0300 Subject: [PATCH 017/430] Add enum with font types --- osu.Game/Skinning/DefaultFont.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 osu.Game/Skinning/DefaultFont.cs diff --git a/osu.Game/Skinning/DefaultFont.cs b/osu.Game/Skinning/DefaultFont.cs new file mode 100644 index 0000000000..69b6aaaff4 --- /dev/null +++ b/osu.Game/Skinning/DefaultFont.cs @@ -0,0 +1,18 @@ +// 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.Skinning.Components; + +namespace osu.Game.Skinning +{ + /// + /// The type of built-in font to use for . + /// + public enum DefaultFont + { + Venera, + Torus, + TorusAlt, + Inter + } +} From b41f30c8689757c3b5850000dccefcb85c475cba Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 3 Dec 2022 22:44:54 +0300 Subject: [PATCH 018/430] Allow changing font of text elements --- .../Components/BeatmapAttributeText.cs | 10 ++--- .../Components/DefaultTextSkinComponent.cs | 42 +++++++++++++++++++ osu.Game/Skinning/Components/TextElement.cs | 11 ++--- 3 files changed, 52 insertions(+), 11 deletions(-) create mode 100644 osu.Game/Skinning/Components/DefaultTextSkinComponent.cs diff --git a/osu.Game/Skinning/Components/BeatmapAttributeText.cs b/osu.Game/Skinning/Components/BeatmapAttributeText.cs index 0a5f0d22cb..71d8f1a40f 100644 --- a/osu.Game/Skinning/Components/BeatmapAttributeText.cs +++ b/osu.Game/Skinning/Components/BeatmapAttributeText.cs @@ -11,12 +11,11 @@ using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Extensions; -using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Localisation; using osu.Game.Resources.Localisation.Web; @@ -24,10 +23,8 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Skinning.Components { [UsedImplicitly] - public partial class BeatmapAttributeText : Container, ISkinnableDrawable + public partial class BeatmapAttributeText : DefaultTextSkinComponent { - public bool UsesFixedAnchor { get; set; } - [SettingSource("Attribute", "The attribute to be displayed.")] public Bindable Attribute { get; } = new Bindable(BeatmapAttribute.StarRating); @@ -67,7 +64,6 @@ namespace osu.Game.Skinning.Components { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Font = OsuFont.Default.With(size: 40) } }; } @@ -122,6 +118,8 @@ namespace osu.Game.Skinning.Components text.Text = LocalisableString.Format(numberedTemplate, args); } + + protected override void SetFont(FontUsage font) => text.Font = font.With(size: 40); } public enum BeatmapAttribute diff --git a/osu.Game/Skinning/Components/DefaultTextSkinComponent.cs b/osu.Game/Skinning/Components/DefaultTextSkinComponent.cs new file mode 100644 index 0000000000..aff400c798 --- /dev/null +++ b/osu.Game/Skinning/Components/DefaultTextSkinComponent.cs @@ -0,0 +1,42 @@ +// 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.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Game.Configuration; +using osu.Game.Graphics; + +namespace osu.Game.Skinning.Components +{ + /// + /// Skin element that contains text and have ability to control its font. + /// + public abstract partial class DefaultTextSkinComponent : Container, ISkinnableDrawable + { + public bool UsesFixedAnchor { get; set; } + + [SettingSource("Font", "Font to use.")] + public Bindable Font { get; } = new Bindable(DefaultFont.Torus); + + protected abstract void SetFont(FontUsage font); + + protected override void LoadComplete() + { + base.LoadComplete(); + Font.BindValueChanged(e => + { + FontUsage f = e.NewValue switch + { + DefaultFont.Venera => OsuFont.Numeric, + DefaultFont.Torus => OsuFont.Torus, + DefaultFont.TorusAlt => OsuFont.TorusAlternate, + DefaultFont.Inter => OsuFont.Inter, + _ => OsuFont.Default + }; + + SetFont(f); + }, true); + } + } +} diff --git a/osu.Game/Skinning/Components/TextElement.cs b/osu.Game/Skinning/Components/TextElement.cs index 74a0acb979..fb779fdb83 100644 --- a/osu.Game/Skinning/Components/TextElement.cs +++ b/osu.Game/Skinning/Components/TextElement.cs @@ -4,7 +4,7 @@ using JetBrains.Annotations; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -12,17 +12,16 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Skinning.Components { [UsedImplicitly] - public partial class TextElement : Container, ISkinnableDrawable + public partial class TextElement : DefaultTextSkinComponent { - public bool UsesFixedAnchor { get; set; } - [SettingSource("Text", "The text to be displayed.")] public Bindable Text { get; } = new Bindable("Circles!"); + private readonly OsuSpriteText text; + public TextElement() { AutoSizeAxes = Axes.Both; - OsuSpriteText text; InternalChildren = new Drawable[] { text = new OsuSpriteText @@ -34,5 +33,7 @@ namespace osu.Game.Skinning.Components }; text.Current.BindTo(Text); } + + protected override void SetFont(FontUsage font) => text.Font = font.With(size: 40); } } From 8174f6be64a7877c0e0788028303236ef01e1ec6 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 3 Dec 2022 23:32:17 +0300 Subject: [PATCH 019/430] Get rid of dublicated enum --- .../Components/DefaultTextSkinComponent.cs | 12 ++---------- osu.Game/Skinning/DefaultFont.cs | 18 ------------------ 2 files changed, 2 insertions(+), 28 deletions(-) delete mode 100644 osu.Game/Skinning/DefaultFont.cs diff --git a/osu.Game/Skinning/Components/DefaultTextSkinComponent.cs b/osu.Game/Skinning/Components/DefaultTextSkinComponent.cs index aff400c798..1fd29effbd 100644 --- a/osu.Game/Skinning/Components/DefaultTextSkinComponent.cs +++ b/osu.Game/Skinning/Components/DefaultTextSkinComponent.cs @@ -17,7 +17,7 @@ namespace osu.Game.Skinning.Components public bool UsesFixedAnchor { get; set; } [SettingSource("Font", "Font to use.")] - public Bindable Font { get; } = new Bindable(DefaultFont.Torus); + public Bindable Font { get; } = new Bindable(Typeface.Torus); protected abstract void SetFont(FontUsage font); @@ -26,15 +26,7 @@ namespace osu.Game.Skinning.Components base.LoadComplete(); Font.BindValueChanged(e => { - FontUsage f = e.NewValue switch - { - DefaultFont.Venera => OsuFont.Numeric, - DefaultFont.Torus => OsuFont.Torus, - DefaultFont.TorusAlt => OsuFont.TorusAlternate, - DefaultFont.Inter => OsuFont.Inter, - _ => OsuFont.Default - }; - + FontUsage f = OsuFont.GetFont(e.NewValue); SetFont(f); }, true); } diff --git a/osu.Game/Skinning/DefaultFont.cs b/osu.Game/Skinning/DefaultFont.cs deleted file mode 100644 index 69b6aaaff4..0000000000 --- a/osu.Game/Skinning/DefaultFont.cs +++ /dev/null @@ -1,18 +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.Skinning.Components; - -namespace osu.Game.Skinning -{ - /// - /// The type of built-in font to use for . - /// - public enum DefaultFont - { - Venera, - Torus, - TorusAlt, - Inter - } -} From b240d15731d7a4205825c78122f298d28cb096c7 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 3 Dec 2022 23:38:50 +0300 Subject: [PATCH 020/430] Fix numeric font --- osu.Game/Skinning/Components/DefaultTextSkinComponent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/Components/DefaultTextSkinComponent.cs b/osu.Game/Skinning/Components/DefaultTextSkinComponent.cs index 1fd29effbd..abe16918c5 100644 --- a/osu.Game/Skinning/Components/DefaultTextSkinComponent.cs +++ b/osu.Game/Skinning/Components/DefaultTextSkinComponent.cs @@ -26,7 +26,7 @@ namespace osu.Game.Skinning.Components base.LoadComplete(); Font.BindValueChanged(e => { - FontUsage f = OsuFont.GetFont(e.NewValue); + FontUsage f = OsuFont.GetFont(e.NewValue, weight: e.NewValue == Typeface.Venera ? FontWeight.Bold : FontWeight.Regular); SetFont(f); }, true); } From 7d7b824f568ac35602b0e39e38223412c4252ded Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 3 Dec 2022 23:42:16 +0300 Subject: [PATCH 021/430] Add description for torus alt --- osu.Game/Graphics/OsuFont.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Graphics/OsuFont.cs b/osu.Game/Graphics/OsuFont.cs index 038ea0f5d7..7aa98ece95 100644 --- a/osu.Game/Graphics/OsuFont.cs +++ b/osu.Game/Graphics/OsuFont.cs @@ -3,6 +3,7 @@ #nullable disable +using System.ComponentModel; using osu.Framework.Graphics.Sprites; namespace osu.Game.Graphics @@ -115,6 +116,8 @@ namespace osu.Game.Graphics { Venera, Torus, + + [Description("Torus (alternate)")] TorusAlternate, Inter, } From 9f4bb3e0cacc3248bf4c76396ad6cb97fca82b46 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Wed, 7 Dec 2022 09:51:22 +0100 Subject: [PATCH 022/430] Add segmend end completions to SliderPath Fix segmentEnds incorrect on shortened paths Revert "Add segmend end completions to SliderPath" This reverts commit cd46ca31f9af73541e05f515018847a588b52775. Revert "Fix segmentEnds incorrect on shortened paths" This reverts commit 98a312ca9661c8d6a61141a4be57265a93b79a2a. From 10b59007107594402c946ba071164ff8975a717a Mon Sep 17 00:00:00 2001 From: OliBomby Date: Thu, 3 Nov 2022 12:25:23 +0100 Subject: [PATCH 023/430] made PathControlPointVisualiser generic --- .../TestScenePathControlPointVisualiser.cs | 4 +- .../TestSceneSliderControlPointPiece.cs | 14 ++-- .../TestSceneSliderSelectionBlueprint.cs | 2 +- .../Editor/TestSceneSliderSnapping.cs | 8 +- .../Editor/TestSceneSliderSplitting.cs | 8 +- .../PathControlPointConnectionPiece.cs | 28 ++++--- .../Components/PathControlPointPiece.cs | 45 +++++----- .../Components/PathControlPointVisualiser.cs | 82 +++++++++---------- .../Sliders/SliderPlacementBlueprint.cs | 4 +- .../Sliders/SliderSelectionBlueprint.cs | 4 +- .../Editing/TestSceneBlueprintOrdering.cs | 2 +- .../Editing/TestSceneComposerSelection.cs | 2 +- 12 files changed, 103 insertions(+), 100 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestScenePathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestScenePathControlPointVisualiser.cs index d1a04e28e5..37561fda85 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestScenePathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestScenePathControlPointVisualiser.cs @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor public partial class TestScenePathControlPointVisualiser : OsuManualInputManagerTestScene { private Slider slider; - private PathControlPointVisualiser visualiser; + private PathControlPointVisualiser visualiser; [SetUp] public void Setup() => Schedule(() => @@ -148,7 +148,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor assertControlPointPathType(3, null); } - private void createVisualiser(bool allowSelection) => AddStep("create visualiser", () => Child = visualiser = new PathControlPointVisualiser(slider, allowSelection) + private void createVisualiser(bool allowSelection) => AddStep("create visualiser", () => Child = visualiser = new PathControlPointVisualiser(slider, allowSelection) { Anchor = Anchor.Centre, Origin = Anchor.Centre diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderControlPointPiece.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderControlPointPiece.cs index 112aab884b..db9eea4127 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderControlPointPiece.cs @@ -159,11 +159,11 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor } private void assertSelectionCount(int count) => - AddAssert($"{count} control point pieces selected", () => this.ChildrenOfType().Count(piece => piece.IsSelected.Value) == count); + AddAssert($"{count} control point pieces selected", () => this.ChildrenOfType>().Count(piece => piece.IsSelected.Value) == count); private void assertSelected(int index) => AddAssert($"{(index + 1).ToOrdinalWords()} control point piece selected", - () => this.ChildrenOfType().Single(piece => piece.ControlPoint == slider.Path.ControlPoints[index]).IsSelected.Value); + () => this.ChildrenOfType>().Single(piece => piece.ControlPoint == slider.Path.ControlPoints[index]).IsSelected.Value); private void moveMouseToRelativePosition(Vector2 relativePosition) => AddStep($"move mouse to {relativePosition}", () => @@ -202,12 +202,12 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor moveMouseToControlPoint(2); AddStep("hold left mouse", () => InputManager.PressButton(MouseButton.Left)); - AddAssert("three control point pieces selected", () => this.ChildrenOfType().Count(piece => piece.IsSelected.Value) == 3); + AddAssert("three control point pieces selected", () => this.ChildrenOfType>().Count(piece => piece.IsSelected.Value) == 3); addMovementStep(new Vector2(450, 50)); AddStep("release left mouse", () => InputManager.ReleaseButton(MouseButton.Left)); - AddAssert("three control point pieces selected", () => this.ChildrenOfType().Count(piece => piece.IsSelected.Value) == 3); + AddAssert("three control point pieces selected", () => this.ChildrenOfType>().Count(piece => piece.IsSelected.Value) == 3); assertControlPointPosition(2, new Vector2(450, 50)); assertControlPointType(2, PathType.PerfectCurve); @@ -236,12 +236,12 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor moveMouseToControlPoint(3); AddStep("hold left mouse", () => InputManager.PressButton(MouseButton.Left)); - AddAssert("three control point pieces selected", () => this.ChildrenOfType().Count(piece => piece.IsSelected.Value) == 3); + AddAssert("three control point pieces selected", () => this.ChildrenOfType>().Count(piece => piece.IsSelected.Value) == 3); addMovementStep(new Vector2(550, 50)); AddStep("release left mouse", () => InputManager.ReleaseButton(MouseButton.Left)); - AddAssert("three control point pieces selected", () => this.ChildrenOfType().Count(piece => piece.IsSelected.Value) == 3); + AddAssert("three control point pieces selected", () => this.ChildrenOfType>().Count(piece => piece.IsSelected.Value) == 3); // note: if the head is part of the selection being moved, the entire slider is moved. // the unselected nodes will therefore change position relative to the slider head. @@ -354,7 +354,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor public new SliderBodyPiece BodyPiece => base.BodyPiece; public new TestSliderCircleOverlay HeadOverlay => (TestSliderCircleOverlay)base.HeadOverlay; public new TestSliderCircleOverlay TailOverlay => (TestSliderCircleOverlay)base.TailOverlay; - public new PathControlPointVisualiser ControlPointVisualiser => base.ControlPointVisualiser; + public new PathControlPointVisualiser ControlPointVisualiser => base.ControlPointVisualiser; public TestSliderBlueprint(Slider slider) : base(slider) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSelectionBlueprint.cs index ad740b2977..8ed77d45d7 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSelectionBlueprint.cs @@ -199,7 +199,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor public new SliderBodyPiece BodyPiece => base.BodyPiece; public new TestSliderCircleOverlay HeadOverlay => (TestSliderCircleOverlay)base.HeadOverlay; public new TestSliderCircleOverlay TailOverlay => (TestSliderCircleOverlay)base.TailOverlay; - public new PathControlPointVisualiser ControlPointVisualiser => base.ControlPointVisualiser; + public new PathControlPointVisualiser ControlPointVisualiser => base.ControlPointVisualiser; public TestSliderBlueprint(Slider slider) : base(slider) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSnapping.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSnapping.cs index e9d50d5118..f262a4334a 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSnapping.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSnapping.cs @@ -72,14 +72,14 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor [Test] public void TestMovingUnsnappedSliderNodesSnaps() { - PathControlPointPiece sliderEnd = null; + PathControlPointPiece sliderEnd = null; assertSliderSnapped(false); AddStep("select slider", () => EditorBeatmap.SelectedHitObjects.Add(slider)); AddStep("select slider end", () => { - sliderEnd = this.ChildrenOfType().Single(piece => piece.ControlPoint == slider.Path.ControlPoints.Last()); + sliderEnd = this.ChildrenOfType>().Single(piece => piece.ControlPoint == slider.Path.ControlPoints.Last()); InputManager.MoveMouseTo(sliderEnd.ScreenSpaceDrawQuad.Centre); }); AddStep("move slider end", () => @@ -99,7 +99,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor AddStep("select slider", () => EditorBeatmap.SelectedHitObjects.Add(slider)); AddStep("move mouse to new point location", () => { - var firstPiece = this.ChildrenOfType().Single(piece => piece.ControlPoint == slider.Path.ControlPoints[0]); + var firstPiece = this.ChildrenOfType>().Single(piece => piece.ControlPoint == slider.Path.ControlPoints[0]); var pos = slider.Path.PositionAt(0.25d) + slider.Position; InputManager.MoveMouseTo(firstPiece.Parent.ToScreenSpace(pos)); }); @@ -120,7 +120,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor AddStep("select slider", () => EditorBeatmap.SelectedHitObjects.Add(slider)); AddStep("move mouse to second control point", () => { - var secondPiece = this.ChildrenOfType().Single(piece => piece.ControlPoint == slider.Path.ControlPoints[1]); + var secondPiece = this.ChildrenOfType>().Single(piece => piece.ControlPoint == slider.Path.ControlPoints[1]); InputManager.MoveMouseTo(secondPiece); }); AddStep("quick delete", () => diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs index b2ac462c8f..6cb77c7b92 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor => Editor.ChildrenOfType().First(); private Slider? slider; - private PathControlPointVisualiser? visualiser; + private PathControlPointVisualiser? visualiser; private const double split_gap = 100; @@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor AddStep("select added slider", () => { EditorBeatmap.SelectedHitObjects.Add(slider); - visualiser = blueprintContainer.SelectionBlueprints.First(o => o.Item == slider).ChildrenOfType().First(); + visualiser = blueprintContainer.SelectionBlueprints.First(o => o.Item == slider).ChildrenOfType>().First(); }); moveMouseToControlPoint(2); @@ -122,7 +122,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor AddStep("select added slider", () => { EditorBeatmap.SelectedHitObjects.Add(slider); - visualiser = blueprintContainer.SelectionBlueprints.First(o => o.Item == slider).ChildrenOfType().First(); + visualiser = blueprintContainer.SelectionBlueprints.First(o => o.Item == slider).ChildrenOfType>().First(); }); moveMouseToControlPoint(2); @@ -190,7 +190,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor AddStep("select added slider", () => { EditorBeatmap.SelectedHitObjects.Add(slider); - visualiser = blueprintContainer.SelectionBlueprints.First(o => o.Item == slider).ChildrenOfType().First(); + visualiser = blueprintContainer.SelectionBlueprints.First(o => o.Item == slider).ChildrenOfType>().First(); }); moveMouseToControlPoint(2); diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointConnectionPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointConnectionPiece.cs index 28e0d650c4..67685d21a7 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointConnectionPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointConnectionPiece.cs @@ -8,34 +8,36 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Lines; using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Objects; using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { /// - /// A visualisation of the line between two s. + /// A visualisation of the line between two s. /// - public partial class PathControlPointConnectionPiece : CompositeDrawable + /// The type of which this visualises. + public partial class PathControlPointConnectionPiece : CompositeDrawable where T : OsuHitObject, IHasPath { public readonly PathControlPoint ControlPoint; private readonly Path path; - private readonly Slider slider; + private readonly T hitObject; public int ControlPointIndex { get; set; } - private IBindable sliderPosition; + private IBindable hitObjectPosition; private IBindable pathVersion; - public PathControlPointConnectionPiece(Slider slider, int controlPointIndex) + public PathControlPointConnectionPiece(T hitObject, int controlPointIndex) { - this.slider = slider; + this.hitObject = hitObject; ControlPointIndex = controlPointIndex; Origin = Anchor.Centre; AutoSizeAxes = Axes.Both; - ControlPoint = slider.Path.ControlPoints[controlPointIndex]; + ControlPoint = hitObject.Path.ControlPoints[controlPointIndex]; InternalChild = path = new SmoothPath { @@ -48,10 +50,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { base.LoadComplete(); - sliderPosition = slider.PositionBindable.GetBoundCopy(); - sliderPosition.BindValueChanged(_ => updateConnectingPath()); + hitObjectPosition = hitObject.PositionBindable.GetBoundCopy(); + hitObjectPosition.BindValueChanged(_ => updateConnectingPath()); - pathVersion = slider.Path.Version.GetBoundCopy(); + pathVersion = hitObject.Path.Version.GetBoundCopy(); pathVersion.BindValueChanged(_ => updateConnectingPath()); updateConnectingPath(); @@ -62,16 +64,16 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components /// private void updateConnectingPath() { - Position = slider.StackedPosition + ControlPoint.Position; + Position = hitObject.StackedPosition + ControlPoint.Position; path.ClearVertices(); int nextIndex = ControlPointIndex + 1; - if (nextIndex == 0 || nextIndex >= slider.Path.ControlPoints.Count) + if (nextIndex == 0 || nextIndex >= hitObject.Path.ControlPoints.Count) return; path.AddVertex(Vector2.Zero); - path.AddVertex(slider.Path.ControlPoints[nextIndex].Position - ControlPoint.Position); + path.AddVertex(hitObject.Path.ControlPoints[nextIndex].Position - ControlPoint.Position); path.OriginPosition = path.PositionInBoundingBox(Vector2.Zero); } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs index d83f35d13f..a4d5c08b8a 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs @@ -29,11 +29,12 @@ using osuTK.Input; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { /// - /// A visualisation of a single in a . + /// A visualisation of a single in an osu hit object with a path. /// - public partial class PathControlPointPiece : BlueprintPiece, IHasTooltip + /// The type of which this visualises. + public partial class PathControlPointPiece : BlueprintPiece, IHasTooltip where T : OsuHitObject, IHasPath { - public Action RequestSelection; + public Action, MouseButtonEvent> RequestSelection; public Action DragStarted; public Action DragInProgress; @@ -44,34 +45,34 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components public readonly BindableBool IsSelected = new BindableBool(); public readonly PathControlPoint ControlPoint; - private readonly Slider slider; + private readonly T hitObject; private readonly Container marker; private readonly Drawable markerRing; [Resolved] private OsuColour colours { get; set; } - private IBindable sliderPosition; - private IBindable sliderScale; + private IBindable hitObjectPosition; + private IBindable hitObjectScale; [UsedImplicitly] - private readonly IBindable sliderVersion; + private readonly IBindable hitObjectVersion; - public PathControlPointPiece(Slider slider, PathControlPoint controlPoint) + public PathControlPointPiece(T hitObject, PathControlPoint controlPoint) { - this.slider = slider; + this.hitObject = hitObject; ControlPoint = controlPoint; - // we don't want to run the path type update on construction as it may inadvertently change the slider. - cachePoints(slider); + // we don't want to run the path type update on construction as it may inadvertently change the hit object. + cachePoints(hitObject); - sliderVersion = slider.Path.Version.GetBoundCopy(); + hitObjectVersion = hitObject.Path.Version.GetBoundCopy(); // schedule ensure that updates are only applied after all operations from a single frame are applied. - // this avoids inadvertently changing the slider path type for batch operations. - sliderVersion.BindValueChanged(_ => Scheduler.AddOnce(() => + // this avoids inadvertently changing the hit object path type for batch operations. + hitObjectVersion.BindValueChanged(_ => Scheduler.AddOnce(() => { - cachePoints(slider); + cachePoints(hitObject); updatePathType(); })); @@ -120,11 +121,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { base.LoadComplete(); - sliderPosition = slider.PositionBindable.GetBoundCopy(); - sliderPosition.BindValueChanged(_ => updateMarkerDisplay()); + hitObjectPosition = hitObject.PositionBindable.GetBoundCopy(); + hitObjectPosition.BindValueChanged(_ => updateMarkerDisplay()); - sliderScale = slider.ScaleBindable.GetBoundCopy(); - sliderScale.BindValueChanged(_ => updateMarkerDisplay()); + hitObjectScale = hitObject.ScaleBindable.GetBoundCopy(); + hitObjectScale.BindValueChanged(_ => updateMarkerDisplay()); IsSelected.BindValueChanged(_ => updateMarkerDisplay()); @@ -212,7 +213,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components protected override void OnDragEnd(DragEndEvent e) => DragEnded?.Invoke(); - private void cachePoints(Slider slider) => PointsInSegment = slider.Path.PointsInSegment(ControlPoint); + private void cachePoints(T hitObject) => PointsInSegment = hitObject.Path.PointsInSegment(ControlPoint); /// /// Handles correction of invalid path types. @@ -239,7 +240,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components /// private void updateMarkerDisplay() { - Position = slider.StackedPosition + ControlPoint.Position; + Position = hitObject.StackedPosition + ControlPoint.Position; markerRing.Alpha = IsSelected.Value ? 1 : 0; @@ -249,7 +250,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components colour = colour.Lighten(1); marker.Colour = colour; - marker.Scale = new Vector2(slider.Scale); + marker.Scale = new Vector2(hitObject.Scale); } private Color4 getColourFromNodeType() diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index 3a175888d9..65b212e976 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -29,15 +29,15 @@ using osuTK.Input; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { - public partial class PathControlPointVisualiser : CompositeDrawable, IKeyBindingHandler, IHasContextMenu + public partial class PathControlPointVisualiser : CompositeDrawable, IKeyBindingHandler, IHasContextMenu where T : OsuHitObject, IHasPath { public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; // allow context menu to appear outside of the playfield. - internal readonly Container Pieces; - internal readonly Container Connections; + internal readonly Container> Pieces; + internal readonly Container> Connections; private readonly IBindableList controlPoints = new BindableList(); - private readonly Slider slider; + private readonly T hitObject; private readonly bool allowSelection; private InputManager inputManager; @@ -48,17 +48,17 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components [Resolved(CanBeNull = true)] private IDistanceSnapProvider snapProvider { get; set; } - public PathControlPointVisualiser(Slider slider, bool allowSelection) + public PathControlPointVisualiser(T hitObject, bool allowSelection) { - this.slider = slider; + this.hitObject = hitObject; this.allowSelection = allowSelection; RelativeSizeAxes = Axes.Both; InternalChildren = new Drawable[] { - Connections = new Container { RelativeSizeAxes = Axes.Both }, - Pieces = new Container { RelativeSizeAxes = Axes.Both } + Connections = new Container> { RelativeSizeAxes = Axes.Both }, + Pieces = new Container> { RelativeSizeAxes = Axes.Both } }; } @@ -69,12 +69,12 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components inputManager = GetContainingInputManager(); controlPoints.CollectionChanged += onControlPointsChanged; - controlPoints.BindTo(slider.Path.ControlPoints); + controlPoints.BindTo(hitObject.Path.ControlPoints); } /// - /// Selects the corresponding to the given , - /// and deselects all other s. + /// Selects the corresponding to the given , + /// and deselects all other s. /// public void SetSelectionTo(PathControlPoint pathControlPoint) { @@ -124,8 +124,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components return true; } - private bool isSplittable(PathControlPointPiece p) => - // A slider can only be split on control points which connect two different slider segments. + private bool isSplittable(PathControlPointPiece p) => + // A hit object can only be split on control points which connect two different path segments. p.ControlPoint.Type.HasValue && p != Pieces.FirstOrDefault() && p != Pieces.LastOrDefault(); private void onControlPointsChanged(object sender, NotifyCollectionChangedEventArgs e) @@ -148,7 +148,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { var point = (PathControlPoint)e.NewItems[i]; - Pieces.Add(new PathControlPointPiece(slider, point).With(d => + Pieces.Add(new PathControlPointPiece(hitObject, point).With(d => { if (allowSelection) d.RequestSelection = selectionRequested; @@ -158,7 +158,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components d.DragEnded = dragEnded; })); - Connections.Add(new PathControlPointConnectionPiece(slider, e.NewStartingIndex + i)); + Connections.Add(new PathControlPointConnectionPiece(hitObject, e.NewStartingIndex + i)); } break; @@ -215,7 +215,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { } - private void selectionRequested(PathControlPointPiece piece, MouseButtonEvent e) + private void selectionRequested(PathControlPointPiece piece, MouseButtonEvent e) { if (e.Button == MouseButton.Left && inputManager.CurrentState.Keyboard.ControlPressed) piece.IsSelected.Toggle(); @@ -230,7 +230,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components /// /// The control point piece that we want to change the path type of. /// The path type we want to assign to the given control point piece. - private void updatePathType(PathControlPointPiece piece, PathType? type) + private void updatePathType(PathControlPointPiece piece, PathType? type) { int indexInSegment = piece.PointsInSegment.IndexOf(piece.ControlPoint); @@ -264,9 +264,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components private void dragStarted(PathControlPoint controlPoint) { - dragStartPositions = slider.Path.ControlPoints.Select(point => point.Position).ToArray(); - dragPathTypes = slider.Path.ControlPoints.Select(point => point.Type).ToArray(); - draggedControlPointIndex = slider.Path.ControlPoints.IndexOf(controlPoint); + dragStartPositions = hitObject.Path.ControlPoints.Select(point => point.Position).ToArray(); + dragPathTypes = hitObject.Path.ControlPoints.Select(point => point.Type).ToArray(); + draggedControlPointIndex = hitObject.Path.ControlPoints.IndexOf(controlPoint); selectedControlPoints = new HashSet(Pieces.Where(piece => piece.IsSelected.Value).Select(piece => piece.ControlPoint)); Debug.Assert(draggedControlPointIndex >= 0); @@ -276,25 +276,25 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components private void dragInProgress(DragEvent e) { - Vector2[] oldControlPoints = slider.Path.ControlPoints.Select(cp => cp.Position).ToArray(); - var oldPosition = slider.Position; - double oldStartTime = slider.StartTime; + Vector2[] oldControlPoints = hitObject.Path.ControlPoints.Select(cp => cp.Position).ToArray(); + var oldPosition = hitObject.Position; + double oldStartTime = hitObject.StartTime; - if (selectedControlPoints.Contains(slider.Path.ControlPoints[0])) + if (selectedControlPoints.Contains(hitObject.Path.ControlPoints[0])) { - // Special handling for selections containing head control point - the position of the slider changes which means the snapped position and time have to be taken into account + // Special handling for selections containing head control point - the position of the hit object changes which means the snapped position and time have to be taken into account Vector2 newHeadPosition = Parent.ToScreenSpace(e.MousePosition + (dragStartPositions[0] - dragStartPositions[draggedControlPointIndex])); var result = snapProvider?.FindSnappedPositionAndTime(newHeadPosition); - Vector2 movementDelta = Parent.ToLocalSpace(result?.ScreenSpacePosition ?? newHeadPosition) - slider.Position; + Vector2 movementDelta = Parent.ToLocalSpace(result?.ScreenSpacePosition ?? newHeadPosition) - hitObject.Position; - slider.Position += movementDelta; - slider.StartTime = result?.Time ?? slider.StartTime; + hitObject.Position += movementDelta; + hitObject.StartTime = result?.Time ?? hitObject.StartTime; - for (int i = 1; i < slider.Path.ControlPoints.Count; i++) + for (int i = 1; i < hitObject.Path.ControlPoints.Count; i++) { - var controlPoint = slider.Path.ControlPoints[i]; - // Since control points are relative to the position of the slider, all points that are _not_ selected + var controlPoint = hitObject.Path.ControlPoints[i]; + // Since control points are relative to the position of the hit object, all points that are _not_ selected // need to be offset _back_ by the delta corresponding to the movement of the head point. // All other selected control points (if any) will move together with the head point // (and so they will not move at all, relative to each other). @@ -306,7 +306,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { var result = snapProvider?.FindSnappedPositionAndTime(Parent.ToScreenSpace(e.MousePosition)); - Vector2 movementDelta = Parent.ToLocalSpace(result?.ScreenSpacePosition ?? Parent.ToScreenSpace(e.MousePosition)) - dragStartPositions[draggedControlPointIndex] - slider.Position; + Vector2 movementDelta = Parent.ToLocalSpace(result?.ScreenSpacePosition ?? Parent.ToScreenSpace(e.MousePosition)) - dragStartPositions[draggedControlPointIndex] - hitObject.Position; for (int i = 0; i < controlPoints.Count; ++i) { @@ -317,23 +317,23 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components } // Snap the path to the current beat divisor before checking length validity. - slider.SnapTo(snapProvider); + hitObject.SnapTo(snapProvider); - if (!slider.Path.HasValidLength) + if (!hitObject.Path.HasValidLength) { - for (int i = 0; i < slider.Path.ControlPoints.Count; i++) - slider.Path.ControlPoints[i].Position = oldControlPoints[i]; + for (int i = 0; i < hitObject.Path.ControlPoints.Count; i++) + hitObject.Path.ControlPoints[i].Position = oldControlPoints[i]; - slider.Position = oldPosition; - slider.StartTime = oldStartTime; + hitObject.Position = oldPosition; + hitObject.StartTime = oldStartTime; // Snap the path length again to undo the invalid length. - slider.SnapTo(snapProvider); + hitObject.SnapTo(snapProvider); return; } // Maintain the path types in case they got defaulted to bezier at some point during the drag. - for (int i = 0; i < slider.Path.ControlPoints.Count; i++) - slider.Path.ControlPoints[i].Type = dragPathTypes[i]; + for (int i = 0; i < hitObject.Path.ControlPoints.Count; i++) + hitObject.Path.ControlPoints[i].Type = dragPathTypes[i]; } private void dragEnded() => changeHandler?.EndChange(); diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs index f91d35e2e1..77393efeb3 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders private SliderBodyPiece bodyPiece; private HitCirclePiece headCirclePiece; private HitCirclePiece tailCirclePiece; - private PathControlPointVisualiser controlPointVisualiser; + private PathControlPointVisualiser controlPointVisualiser; private InputManager inputManager; @@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders bodyPiece = new SliderBodyPiece(), headCirclePiece = new HitCirclePiece(), tailCirclePiece = new HitCirclePiece(), - controlPointVisualiser = new PathControlPointVisualiser(HitObject, false) + controlPointVisualiser = new PathControlPointVisualiser(HitObject, false) }; setState(SliderPlacementState.Initial); diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index a51c223785..b37041674e 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders protected SliderCircleOverlay TailOverlay { get; private set; } [CanBeNull] - protected PathControlPointVisualiser ControlPointVisualiser { get; private set; } + protected PathControlPointVisualiser ControlPointVisualiser { get; private set; } [Resolved(CanBeNull = true)] private IDistanceSnapProvider snapProvider { get; set; } @@ -147,7 +147,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { if (ControlPointVisualiser == null) { - AddInternal(ControlPointVisualiser = new PathControlPointVisualiser(HitObject, true) + AddInternal(ControlPointVisualiser = new PathControlPointVisualiser(HitObject, true) { RemoveControlPointsRequested = removeControlPoints, SplitControlPointsRequested = splitControlPoints diff --git a/osu.Game.Tests/Visual/Editing/TestSceneBlueprintOrdering.cs b/osu.Game.Tests/Visual/Editing/TestSceneBlueprintOrdering.cs index 7728adecae..8b598a6a24 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneBlueprintOrdering.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneBlueprintOrdering.cs @@ -66,7 +66,7 @@ namespace osu.Game.Tests.Visual.Editing AddStep("move mouse to common point", () => { - var pos = blueprintContainer.ChildrenOfType().ElementAt(1).ScreenSpaceDrawQuad.Centre; + var pos = blueprintContainer.ChildrenOfType>().ElementAt(1).ScreenSpaceDrawQuad.Centre; InputManager.MoveMouseTo(pos); }); AddStep("right click", () => InputManager.Click(MouseButton.Right)); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneComposerSelection.cs b/osu.Game.Tests/Visual/Editing/TestSceneComposerSelection.cs index ffb8a67c68..b14025c9d8 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneComposerSelection.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneComposerSelection.cs @@ -286,7 +286,7 @@ namespace osu.Game.Tests.Visual.Editing AddStep("move mouse to controlpoint", () => { - var pos = blueprintContainer.ChildrenOfType().ElementAt(1).ScreenSpaceDrawQuad.Centre; + var pos = blueprintContainer.ChildrenOfType>().ElementAt(1).ScreenSpaceDrawQuad.Centre; InputManager.MoveMouseTo(pos); }); AddStep("hold shift", () => InputManager.PressKey(Key.ShiftLeft)); From d458c3a012264fa8095db2d24345ce31dfbf3fe1 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Wed, 7 Dec 2022 10:11:57 +0100 Subject: [PATCH 024/430] Fix variable which didnt get renamed --- .../Blueprints/Sliders/Components/PathControlPointVisualiser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index 65b212e976..10ee7a9a05 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -248,7 +248,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components break; } - slider.Path.ExpectedDistance.Value = null; + hitObject.Path.ExpectedDistance.Value = null; piece.ControlPoint.Type = type; } From 407b0a0ad3c29948162df5eae5e230335f93de7b Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Mon, 19 Dec 2022 11:30:23 +0100 Subject: [PATCH 025/430] 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 026/430] 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 027/430] 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 028/430] 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 029/430] 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 39221a52dacdc4232f071ab03cac9c70aea8ada6 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 5 Jan 2023 12:49:45 +0300 Subject: [PATCH 030/430] Fix advanced statistics display using decoupled ruleset bindable for difficulty calculation --- osu.Game/OsuGameBase.cs | 5 ++++- .../Screens/Select/Details/AdvancedStats.cs | 20 +++++++++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 36e248c1f2..83a32dd557 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -160,9 +160,12 @@ namespace osu.Game protected Bindable Beatmap { get; private set; } // cached via load() method + /// + /// The current ruleset selection for the local user. + /// [Cached] [Cached(typeof(IBindable))] - protected readonly Bindable Ruleset = new Bindable(); + protected internal readonly Bindable Ruleset = new Bindable(); /// /// The current mod selection for the local user. diff --git a/osu.Game/Screens/Select/Details/AdvancedStats.cs b/osu.Game/Screens/Select/Details/AdvancedStats.cs index 5d0588e67b..3d45679604 100644 --- a/osu.Game/Screens/Select/Details/AdvancedStats.cs +++ b/osu.Game/Screens/Select/Details/AdvancedStats.cs @@ -30,14 +30,16 @@ namespace osu.Game.Screens.Select.Details { public partial class AdvancedStats : Container { + [Resolved] + private BeatmapDifficultyCache difficultyCache { get; set; } + [Resolved] private IBindable> mods { get; set; } [Resolved] - private IBindable ruleset { get; set; } + private OsuGameBase game { get; set; } - [Resolved] - private BeatmapDifficultyCache difficultyCache { get; set; } + private IBindable gameRuleset; protected readonly StatisticRow FirstValue, HpDrain, Accuracy, ApproachRate; private readonly StatisticRow starDifficulty; @@ -84,7 +86,13 @@ namespace osu.Game.Screens.Select.Details { base.LoadComplete(); - ruleset.BindValueChanged(_ => updateStatistics()); + // the cached ruleset bindable might be a decoupled bindable provided by SongSelect, + // which we can't rely on in combination with the game-wide selected mods list, + // since mods could be updated to the new ruleset instances while the decoupled bindable is held behind, + // therefore resulting in performing difficulty calculation with invalid states. + gameRuleset = game.Ruleset.GetBoundCopy(); + gameRuleset.BindValueChanged(_ => updateStatistics()); + mods.BindValueChanged(modsChanged, true); } @@ -151,8 +159,8 @@ namespace osu.Game.Screens.Select.Details starDifficultyCancellationSource = new CancellationTokenSource(); - var normalStarDifficultyTask = difficultyCache.GetDifficultyAsync(BeatmapInfo, ruleset.Value, null, starDifficultyCancellationSource.Token); - var moddedStarDifficultyTask = difficultyCache.GetDifficultyAsync(BeatmapInfo, ruleset.Value, mods.Value, starDifficultyCancellationSource.Token); + var normalStarDifficultyTask = difficultyCache.GetDifficultyAsync(BeatmapInfo, gameRuleset.Value, null, starDifficultyCancellationSource.Token); + var moddedStarDifficultyTask = difficultyCache.GetDifficultyAsync(BeatmapInfo, gameRuleset.Value, mods.Value, starDifficultyCancellationSource.Token); Task.WhenAll(normalStarDifficultyTask, moddedStarDifficultyTask).ContinueWith(_ => Schedule(() => { From 8f37e69dc4e8c7804098a7415deb838a33f4933e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 5 Jan 2023 12:50:38 +0300 Subject: [PATCH 031/430] Schedule difficulty calculation to avoid performing with incomplete state updates --- osu.Game/Screens/Select/Details/AdvancedStats.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/Details/AdvancedStats.cs b/osu.Game/Screens/Select/Details/AdvancedStats.cs index 3d45679604..a383298faa 100644 --- a/osu.Game/Screens/Select/Details/AdvancedStats.cs +++ b/osu.Game/Screens/Select/Details/AdvancedStats.cs @@ -150,7 +150,14 @@ namespace osu.Game.Screens.Select.Details private CancellationTokenSource starDifficultyCancellationSource; - private void updateStarDifficulty() + /// + /// Updates the displayed star difficulty statistics with the values provided by the currently-selected beatmap, ruleset, and selected mods. + /// + /// + /// This is scheduled to avoid scenarios wherein a ruleset changes first before selected mods do, + /// potentially resulting in failure during difficulty calculation due to incomplete bindable state updates. + /// + private void updateStarDifficulty() => Scheduler.AddOnce(() => { starDifficultyCancellationSource?.Cancel(); @@ -172,7 +179,7 @@ namespace osu.Game.Screens.Select.Details starDifficulty.Value = ((float)normalDifficulty.Value.Stars, (float)moddedDifficulty.Value.Stars); }), starDifficultyCancellationSource.Token, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Current); - } + }); protected override void Dispose(bool isDisposing) { From 93a57b6871a98d94f898cfa6afbf5504ab9932c9 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sat, 7 Jan 2023 11:28:09 -0800 Subject: [PATCH 032/430] 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 033/430] 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 034/430] 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 035/430] 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 036/430] 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 037/430] 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 038/430] 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 039/430] 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 040/430] 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 041/430] 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 042/430] 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 043/430] 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 044/430] 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 045/430] 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 046/430] 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 047/430] 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 048/430] 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 049/430] 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 050/430] 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 051/430] 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 052/430] 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 053/430] 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 054/430] 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 055/430] 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 38bb7ac0c7901cbca12a4f787fe2d28eaa0591a8 Mon Sep 17 00:00:00 2001 From: Wleter Date: Tue, 10 Jan 2023 21:16:34 +0100 Subject: [PATCH 056/430] add fields for path's end location --- .../Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs | 4 ++++ osu.Game.Rulesets.Osu/Skinning/SliderBody.cs | 6 ++++++ osu.Game.Rulesets.Osu/Skinning/SnakingSliderBody.cs | 8 ++++++++ 3 files changed, 18 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs index ecd840dda6..c44bbbfa03 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs @@ -22,6 +22,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components /// public Vector2 PathStartLocation => body.PathOffset; + /// + /// Offset in absolute (local) coordinates from the end of the curve. + /// + public Vector2 PathEndLocation => body.PathEndOffset; public SliderBodyPiece() { InternalChild = body = new ManualSliderBody diff --git a/osu.Game.Rulesets.Osu/Skinning/SliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/SliderBody.cs index 283687adfd..8a54723a8e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SliderBody.cs @@ -31,6 +31,12 @@ namespace osu.Game.Rulesets.Osu.Skinning /// public virtual Vector2 PathOffset => path.PositionInBoundingBox(path.Vertices[0]); + /// + /// Offset in absolute coordinates from the end of the curve. + /// + public virtual Vector2 PathEndOffset => path.PositionInBoundingBox(path.Vertices[^1]); + + /// /// Used to colour the path. /// diff --git a/osu.Game.Rulesets.Osu/Skinning/SnakingSliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/SnakingSliderBody.cs index f8ee465cd6..0b7acc1f47 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SnakingSliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SnakingSliderBody.cs @@ -43,6 +43,8 @@ namespace osu.Game.Rulesets.Osu.Skinning public override Vector2 PathOffset => snakedPathOffset; + public override Vector2 PathEndOffset => snakedPathEndOffset; + /// /// The top-left position of the path when fully snaked. /// @@ -53,6 +55,11 @@ namespace osu.Game.Rulesets.Osu.Skinning /// private Vector2 snakedPathOffset; + /// + /// The offset of the end of path from when fully snaked. + /// + private Vector2 snakedPathEndOffset; + private DrawableSlider drawableSlider = null!; [BackgroundDependencyLoader] @@ -109,6 +116,7 @@ namespace osu.Game.Rulesets.Osu.Skinning snakedPosition = Path.PositionInBoundingBox(Vector2.Zero); snakedPathOffset = Path.PositionInBoundingBox(Path.Vertices[0]); + snakedPathEndOffset = Path.PositionInBoundingBox(Path.Vertices[^1]); double lastSnakedStart = SnakedStart ?? 0; double lastSnakedEnd = SnakedEnd ?? 0; From e5863fbaf1f4f9f7918459aff1a38e0941752301 Mon Sep 17 00:00:00 2001 From: Wleter Date: Tue, 10 Jan 2023 21:20:09 +0100 Subject: [PATCH 057/430] add ScreenSpaceEndPoint field --- .../Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs | 4 ++++ osu.Game/Rulesets/Edit/HitObjectSelectionBlueprint.cs | 2 ++ osu.Game/Rulesets/Edit/SelectionBlueprint.cs | 5 +++++ 3 files changed, 11 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index a51c223785..3737a44ad2 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -409,6 +409,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders public override Vector2 ScreenSpaceSelectionPoint => DrawableObject.SliderBody?.ToScreenSpace(DrawableObject.SliderBody.PathOffset) ?? BodyPiece.ToScreenSpace(BodyPiece.PathStartLocation); + + public override Vector2 ScreenSpaceEndPoint => DrawableObject.SliderBody?.ToScreenSpace(DrawableObject.SliderBody.PathEndOffset) + ?? BodyPiece.ToScreenSpace(BodyPiece.PathEndLocation); + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => BodyPiece.ReceivePositionalInputAt(screenSpacePos) || ControlPointVisualiser?.Pieces.Any(p => p.ReceivePositionalInputAt(screenSpacePos)) == true; diff --git a/osu.Game/Rulesets/Edit/HitObjectSelectionBlueprint.cs b/osu.Game/Rulesets/Edit/HitObjectSelectionBlueprint.cs index 93b889792b..3aa086582f 100644 --- a/osu.Game/Rulesets/Edit/HitObjectSelectionBlueprint.cs +++ b/osu.Game/Rulesets/Edit/HitObjectSelectionBlueprint.cs @@ -48,6 +48,8 @@ namespace osu.Game.Rulesets.Edit public override Vector2 ScreenSpaceSelectionPoint => DrawableObject.ScreenSpaceDrawQuad.Centre; + public override Vector2 ScreenSpaceEndPoint => DrawableObject.ScreenSpaceDrawQuad.Centre; + public override Quad SelectionQuad => DrawableObject.ScreenSpaceDrawQuad; } diff --git a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs index 4e0e45e0f5..a27a59be34 100644 --- a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs +++ b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs @@ -129,6 +129,11 @@ namespace osu.Game.Rulesets.Edit /// public virtual Vector2 ScreenSpaceSelectionPoint => ScreenSpaceDrawQuad.Centre; + /// + /// The screen-space point that mark end of this . + /// + public virtual Vector2 ScreenSpaceEndPoint => ScreenSpaceDrawQuad.Centre; + /// /// The screen-space quad that outlines this for selections. /// From 88060a3ea097d3dbad513e08f582288825cbaf9b Mon Sep 17 00:00:00 2001 From: Wleter Date: Tue, 10 Jan 2023 21:21:09 +0100 Subject: [PATCH 058/430] add snapping for slider's end --- .../Compose/Components/BlueprintContainer.cs | 60 +++++++++++++------ 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index 77892f21e6..826a16b83b 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -440,6 +440,7 @@ namespace osu.Game.Screens.Edit.Compose.Components #region Selection Movement private Vector2[] movementBlueprintOriginalPositions; + private Vector2[] movementBlueprintEndPositions; private SelectionBlueprint[] movementBlueprints; private bool isDraggingBlueprint; @@ -459,7 +460,12 @@ namespace osu.Game.Screens.Edit.Compose.Components // Movement is tracked from the blueprint of the earliest item, since it only makes sense to distance snap from that item movementBlueprints = SortForMovement(SelectionHandler.SelectedBlueprints).ToArray(); - movementBlueprintOriginalPositions = movementBlueprints.Select(m => m.ScreenSpaceSelectionPoint).ToArray(); + movementBlueprintOriginalPositions = movementBlueprints.Select(m => m.ScreenSpaceSelectionPoint) + .ToArray(); + movementBlueprintEndPositions = movementBlueprints.Where(m => m.ScreenSpaceSelectionPoint != m.ScreenSpaceEndPoint) + .Select(m => m.ScreenSpaceEndPoint) + .ToArray(); + return true; } @@ -470,6 +476,33 @@ namespace osu.Game.Screens.Edit.Compose.Components /// Sorted blueprints. protected virtual IEnumerable> SortForMovement(IReadOnlyList> blueprints) => blueprints; + /// + /// Check for positional snap for every given positions. + /// + /// Distance traveled since start of dragging action. + /// The positions to check for snapping before start of dragging action. + /// The positions to check for snapping at the current time. + /// Whether found object to snap to. + private bool checkSnappingForNearbyObjects(Vector2 distanceTraveled, Vector2[] originalPositions, Vector2[] currentPositions) + { + for (int i = 0; i < originalPositions.Length; i++) + { + Vector2 originalPosition = originalPositions[i]; + var testPosition = originalPosition + distanceTraveled; + + var positionalResult = snapProvider.FindSnappedPositionAndTime(testPosition, SnapType.NearbyObjects); + + if (positionalResult.ScreenSpacePosition == testPosition) continue; + + var delta = positionalResult.ScreenSpacePosition - currentPositions[i]; + + // attempt to move the objects, and abort any time based snapping if we can. + if (SelectionHandler.HandleMovement(new MoveSelectionEvent(movementBlueprints[i], delta))) + return true; + } + return false; + } + /// /// Moves the current selected blueprints. /// @@ -482,33 +515,24 @@ namespace osu.Game.Screens.Edit.Compose.Components Debug.Assert(movementBlueprintOriginalPositions != null); - Vector2 distanceTravelled = e.ScreenSpaceMousePosition - e.ScreenSpaceMouseDownPosition; + Vector2 distanceTraveled = e.ScreenSpaceMousePosition - e.ScreenSpaceMouseDownPosition; if (snapProvider != null) { - // check for positional snap for every object in selection (for things like object-object snapping) - for (int i = 0; i < movementBlueprintOriginalPositions.Length; i++) - { - Vector2 originalPosition = movementBlueprintOriginalPositions[i]; - var testPosition = originalPosition + distanceTravelled; + var currentSelectionPointPositions = movementBlueprints.Select(m => m.ScreenSpaceSelectionPoint).ToArray(); + if (checkSnappingForNearbyObjects(distanceTraveled, movementBlueprintOriginalPositions, currentSelectionPointPositions)) + return true; - var positionalResult = snapProvider.FindSnappedPositionAndTime(testPosition, SnapType.NearbyObjects); - - if (positionalResult.ScreenSpacePosition == testPosition) continue; - - var delta = positionalResult.ScreenSpacePosition - movementBlueprints[i].ScreenSpaceSelectionPoint; - - // attempt to move the objects, and abort any time based snapping if we can. - if (SelectionHandler.HandleMovement(new MoveSelectionEvent(movementBlueprints[i], delta))) - return true; - } + var currentEndPointPositions = movementBlueprints.Select(m => m.ScreenSpaceEndPoint).ToArray(); + if (checkSnappingForNearbyObjects(distanceTraveled, movementBlueprintEndPositions, currentEndPointPositions)) + return true; } // if no positional snapping could be performed, try unrestricted snapping from the earliest // item in the selection. // The final movement position, relative to movementBlueprintOriginalPosition. - Vector2 movePosition = movementBlueprintOriginalPositions.First() + distanceTravelled; + Vector2 movePosition = movementBlueprintOriginalPositions.First() + distanceTraveled; // Retrieve a snapped position. var result = snapProvider?.FindSnappedPositionAndTime(movePosition, ~SnapType.NearbyObjects); 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 059/430] 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 060/430] 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 061/430] 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 062/430] 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 063/430] 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 064/430] 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 065/430] 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 066/430] 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 067/430] 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 068/430] 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 069/430] 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 070/430] 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 071/430] 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 072/430] 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 23ea77cb74034f2e19071a4758329efc8fad4ba0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 17:03:04 +0900 Subject: [PATCH 073/430] Use `ScoreProcessor` to fetch accuracy rather than calculating manually --- .../Rulesets/Mods/ModAccuracyChallenge.cs | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs index 74a9a205a0..732f54e356 100644 --- a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs +++ b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs @@ -5,23 +5,32 @@ using System; using System.Globalization; 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; +using osu.Game.Scoring; namespace osu.Game.Rulesets.Mods { - public class ModAccuracyChallenge : ModFailCondition + public class ModAccuracyChallenge : ModFailCondition, IApplicableToScoreProcessor { public override string Name => "Accuracy Challenge"; + public override string Acronym => "AC"; - public override string Description => "Fail the map if you don't maintain a certain accuracy."; + + public override LocalisableString Description => "Fail if your accuracy drops too low!"; + public override ModType Type => ModType.DifficultyIncrease; + public override double ScoreMultiplier => 1.0; + public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(ModEasyWithExtraLives), typeof(ModPerfect) }).ToArray(); + public override bool RequiresConfiguration => false; + 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))] @@ -34,9 +43,14 @@ namespace osu.Game.Rulesets.Mods Value = 0.9, }; - private double baseScore; - private double maxBaseScore; - private double accuracy => maxBaseScore > 0 ? baseScore / maxBaseScore : 1; + private ScoreProcessor scoreProcessor = null!; + + public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) + { + this.scoreProcessor = scoreProcessor; + } + + public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank; protected override bool FailCondition(HealthProcessor healthProcessor, JudgementResult result) { @@ -44,14 +58,11 @@ namespace osu.Game.Rulesets.Mods if (!result.Type.IsScorable() || result.Type.IsBonus()) return false; - baseScore += result.Type.IsHit() ? result.Judgement.NumericResultFor(result) : 0; - maxBaseScore += result.Judgement.MaxNumericResult; - - return accuracy < MinimumAccuracy.Value; + return scoreProcessor.Accuracy.Value < MinimumAccuracy.Value; } } - public class PercentSlider : OsuSliderBar + public partial class PercentSlider : OsuSliderBar { public PercentSlider() { From dfbbc4002c0fccf6ecdedea8a609972efa0fdd45 Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Tue, 17 Jan 2023 10:22:58 -0500 Subject: [PATCH 074/430] address test failure --- .../Mods/OsuModAccuracyChallenge.cs | 14 ++++++++++++++ osu.Game.Rulesets.Osu/OsuRuleset.cs | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Rulesets.Osu/Mods/OsuModAccuracyChallenge.cs diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAccuracyChallenge.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAccuracyChallenge.cs new file mode 100644 index 0000000000..5b79753632 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Mods/OsuModAccuracyChallenge.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. + +using System; +using System.Linq; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Rulesets.Osu.Mods +{ + public class OsuModAccuracyChallenge : ModAccuracyChallenge + { + public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModAutopilot)).ToArray(); + } +} diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 6417b557f4..48056a49de 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -165,7 +165,7 @@ namespace osu.Game.Rulesets.Osu new OsuModHidden(), new MultiMod(new OsuModFlashlight(), new OsuModBlinds()), new OsuModStrictTracking(), - new ModAccuracyChallenge(), + new OsuModAccuracyChallenge(), }; case ModType.Conversion: From 0b1e5c0f53f4470ab9ead7d1b99c35d5fca2c790 Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Tue, 17 Jan 2023 10:23:57 -0500 Subject: [PATCH 075/430] lambdaify function --- osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs index 732f54e356..78e6acf23a 100644 --- a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs +++ b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs @@ -45,10 +45,7 @@ namespace osu.Game.Rulesets.Mods private ScoreProcessor scoreProcessor = null!; - public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) - { - this.scoreProcessor = scoreProcessor; - } + public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) => this.scoreProcessor = scoreProcessor; public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank; From b8e6a2d87b86c88f243bd67ee6379d572ca1c5b3 Mon Sep 17 00:00:00 2001 From: Wleter Date: Tue, 17 Jan 2023 20:41:49 +0100 Subject: [PATCH 076/430] filter currentEndPointPositions --- .../Compose/Components/BlueprintContainer.cs | 64 ++++++++++--------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index 826a16b83b..07cfd9fe0a 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -440,7 +440,7 @@ namespace osu.Game.Screens.Edit.Compose.Components #region Selection Movement private Vector2[] movementBlueprintOriginalPositions; - private Vector2[] movementBlueprintEndPositions; + private Vector2[] movementBlueprintOriginalEndPositions; private SelectionBlueprint[] movementBlueprints; private bool isDraggingBlueprint; @@ -462,7 +462,7 @@ namespace osu.Game.Screens.Edit.Compose.Components movementBlueprints = SortForMovement(SelectionHandler.SelectedBlueprints).ToArray(); movementBlueprintOriginalPositions = movementBlueprints.Select(m => m.ScreenSpaceSelectionPoint) .ToArray(); - movementBlueprintEndPositions = movementBlueprints.Where(m => m.ScreenSpaceSelectionPoint != m.ScreenSpaceEndPoint) + movementBlueprintOriginalEndPositions = movementBlueprints.Where(m => m.ScreenSpaceSelectionPoint != m.ScreenSpaceEndPoint) .Select(m => m.ScreenSpaceEndPoint) .ToArray(); @@ -476,33 +476,6 @@ namespace osu.Game.Screens.Edit.Compose.Components /// Sorted blueprints. protected virtual IEnumerable> SortForMovement(IReadOnlyList> blueprints) => blueprints; - /// - /// Check for positional snap for every given positions. - /// - /// Distance traveled since start of dragging action. - /// The positions to check for snapping before start of dragging action. - /// The positions to check for snapping at the current time. - /// Whether found object to snap to. - private bool checkSnappingForNearbyObjects(Vector2 distanceTraveled, Vector2[] originalPositions, Vector2[] currentPositions) - { - for (int i = 0; i < originalPositions.Length; i++) - { - Vector2 originalPosition = originalPositions[i]; - var testPosition = originalPosition + distanceTraveled; - - var positionalResult = snapProvider.FindSnappedPositionAndTime(testPosition, SnapType.NearbyObjects); - - if (positionalResult.ScreenSpacePosition == testPosition) continue; - - var delta = positionalResult.ScreenSpacePosition - currentPositions[i]; - - // attempt to move the objects, and abort any time based snapping if we can. - if (SelectionHandler.HandleMovement(new MoveSelectionEvent(movementBlueprints[i], delta))) - return true; - } - return false; - } - /// /// Moves the current selected blueprints. /// @@ -523,8 +496,10 @@ namespace osu.Game.Screens.Edit.Compose.Components if (checkSnappingForNearbyObjects(distanceTraveled, movementBlueprintOriginalPositions, currentSelectionPointPositions)) return true; - var currentEndPointPositions = movementBlueprints.Select(m => m.ScreenSpaceEndPoint).ToArray(); - if (checkSnappingForNearbyObjects(distanceTraveled, movementBlueprintEndPositions, currentEndPointPositions)) + var currentEndPointPositions = movementBlueprints.Where(m => m.ScreenSpaceSelectionPoint != m.ScreenSpaceEndPoint) + .Select(m => m.ScreenSpaceEndPoint) + .ToArray(); + if (checkSnappingForNearbyObjects(distanceTraveled, movementBlueprintOriginalEndPositions, currentEndPointPositions)) return true; } @@ -545,6 +520,33 @@ namespace osu.Game.Screens.Edit.Compose.Components return ApplySnapResult(movementBlueprints, result); } + /// + /// Check for positional snap for every given positions. + /// + /// Distance traveled since start of dragging action. + /// The position of objects before start of dragging action. + /// The positions of object at the current time. + /// Whether found object to snap to. + private bool checkSnappingForNearbyObjects(Vector2 distanceTraveled, Vector2[] originalPositions, Vector2[] currentPositions) + { + for (int i = 0; i < originalPositions.Length; i++) + { + Vector2 originalPosition = originalPositions[i]; + var testPosition = originalPosition + distanceTraveled; + + var positionalResult = snapProvider.FindSnappedPositionAndTime(testPosition, SnapType.NearbyObjects); + + if (positionalResult.ScreenSpacePosition == testPosition) continue; + + var delta = positionalResult.ScreenSpacePosition - currentPositions[i]; + + // attempt to move the objects, and abort any time based snapping if we can. + if (SelectionHandler.HandleMovement(new MoveSelectionEvent(movementBlueprints[i], delta))) + return true; + } + return false; + } + protected virtual bool ApplySnapResult(SelectionBlueprint[] blueprints, SnapResult result) => SelectionHandler.HandleMovement(new MoveSelectionEvent(blueprints.First(), result.ScreenSpacePosition - blueprints.First().ScreenSpaceSelectionPoint)); From 00f15d19f969d1977b9834a75ff781b8a4d0dc19 Mon Sep 17 00:00:00 2001 From: Wleter Date: Tue, 17 Jan 2023 21:11:21 +0100 Subject: [PATCH 077/430] fix double newlines --- .../Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs | 1 + .../Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs | 1 - osu.Game.Rulesets.Osu/Skinning/SliderBody.cs | 1 - 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs index c44bbbfa03..4ff38cd1f8 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs @@ -26,6 +26,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components /// Offset in absolute (local) coordinates from the end of the curve. /// public Vector2 PathEndLocation => body.PathEndOffset; + public SliderBodyPiece() { InternalChild = body = new ManualSliderBody diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 3737a44ad2..90c97e2752 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -409,7 +409,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders public override Vector2 ScreenSpaceSelectionPoint => DrawableObject.SliderBody?.ToScreenSpace(DrawableObject.SliderBody.PathOffset) ?? BodyPiece.ToScreenSpace(BodyPiece.PathStartLocation); - public override Vector2 ScreenSpaceEndPoint => DrawableObject.SliderBody?.ToScreenSpace(DrawableObject.SliderBody.PathEndOffset) ?? BodyPiece.ToScreenSpace(BodyPiece.PathEndLocation); diff --git a/osu.Game.Rulesets.Osu/Skinning/SliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/SliderBody.cs index 8a54723a8e..e7885e65de 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SliderBody.cs @@ -35,7 +35,6 @@ namespace osu.Game.Rulesets.Osu.Skinning /// Offset in absolute coordinates from the end of the curve. /// public virtual Vector2 PathEndOffset => path.PositionInBoundingBox(path.Vertices[^1]); - /// /// Used to colour the path. From 788033e1b89997142f9d74089b19bd7821b08119 Mon Sep 17 00:00:00 2001 From: Wleter Date: Tue, 17 Jan 2023 21:13:54 +0100 Subject: [PATCH 078/430] fix unnecessary newline --- .../Screens/Edit/Compose/Components/BlueprintContainer.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index 07cfd9fe0a..113dffbcb0 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -460,11 +460,9 @@ namespace osu.Game.Screens.Edit.Compose.Components // Movement is tracked from the blueprint of the earliest item, since it only makes sense to distance snap from that item movementBlueprints = SortForMovement(SelectionHandler.SelectedBlueprints).ToArray(); - movementBlueprintOriginalPositions = movementBlueprints.Select(m => m.ScreenSpaceSelectionPoint) - .ToArray(); + movementBlueprintOriginalPositions = movementBlueprints.Select(m => m.ScreenSpaceSelectionPoint).ToArray(); movementBlueprintOriginalEndPositions = movementBlueprints.Where(m => m.ScreenSpaceSelectionPoint != m.ScreenSpaceEndPoint) - .Select(m => m.ScreenSpaceEndPoint) - .ToArray(); + .Select(m => m.ScreenSpaceEndPoint).ToArray(); return true; } From 92a755c5da93c4077ace0342b784539e21072941 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Tue, 17 Jan 2023 22:16:59 +0100 Subject: [PATCH 079/430] 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 ecb4727aeca1d1011a793ccab2b85f8f67bc6dc8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 17:33:14 +0900 Subject: [PATCH 080/430] Fix formatting issues --- .../Blueprints/Sliders/Components/SliderBodyPiece.cs | 2 +- .../Blueprints/Sliders/SliderSelectionBlueprint.cs | 2 +- .../Edit/Compose/Components/BlueprintContainer.cs | 11 +++++++---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs index 4ff38cd1f8..68a44eb2f8 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components /// Offset in absolute (local) coordinates from the end of the curve. /// public Vector2 PathEndLocation => body.PathEndOffset; - + public SliderBodyPiece() { InternalChild = body = new ManualSliderBody diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 90c97e2752..634897e3d5 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -410,7 +410,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders ?? BodyPiece.ToScreenSpace(BodyPiece.PathStartLocation); public override Vector2 ScreenSpaceEndPoint => DrawableObject.SliderBody?.ToScreenSpace(DrawableObject.SliderBody.PathEndOffset) - ?? BodyPiece.ToScreenSpace(BodyPiece.PathEndLocation); + ?? BodyPiece.ToScreenSpace(BodyPiece.PathEndLocation); public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => BodyPiece.ReceivePositionalInputAt(screenSpacePos) || ControlPointVisualiser?.Pieces.Any(p => p.ReceivePositionalInputAt(screenSpacePos)) == true; diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index 113dffbcb0..c9d9f2266a 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -462,8 +462,8 @@ namespace osu.Game.Screens.Edit.Compose.Components movementBlueprints = SortForMovement(SelectionHandler.SelectedBlueprints).ToArray(); movementBlueprintOriginalPositions = movementBlueprints.Select(m => m.ScreenSpaceSelectionPoint).ToArray(); movementBlueprintOriginalEndPositions = movementBlueprints.Where(m => m.ScreenSpaceSelectionPoint != m.ScreenSpaceEndPoint) - .Select(m => m.ScreenSpaceEndPoint).ToArray(); - + .Select(m => m.ScreenSpaceEndPoint).ToArray(); + return true; } @@ -491,12 +491,14 @@ namespace osu.Game.Screens.Edit.Compose.Components if (snapProvider != null) { var currentSelectionPointPositions = movementBlueprints.Select(m => m.ScreenSpaceSelectionPoint).ToArray(); + if (checkSnappingForNearbyObjects(distanceTraveled, movementBlueprintOriginalPositions, currentSelectionPointPositions)) return true; var currentEndPointPositions = movementBlueprints.Where(m => m.ScreenSpaceSelectionPoint != m.ScreenSpaceEndPoint) - .Select(m => m.ScreenSpaceEndPoint) - .ToArray(); + .Select(m => m.ScreenSpaceEndPoint) + .ToArray(); + if (checkSnappingForNearbyObjects(distanceTraveled, movementBlueprintOriginalEndPositions, currentEndPointPositions)) return true; } @@ -542,6 +544,7 @@ namespace osu.Game.Screens.Edit.Compose.Components if (SelectionHandler.HandleMovement(new MoveSelectionEvent(movementBlueprints[i], delta))) return true; } + return false; } From 522bb8bccafc93603d068775b6c3a28cd3b58c25 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 18:08:58 +0900 Subject: [PATCH 081/430] Use `ComputeAccuracy` to get imminent accuracy --- osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs | 15 +++++++++++++-- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 18 +++++++++++------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs index 78e6acf23a..02d4fb4d67 100644 --- a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs +++ b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs @@ -51,11 +51,22 @@ namespace osu.Game.Rulesets.Mods protected override bool FailCondition(HealthProcessor healthProcessor, JudgementResult result) { - // accuracy calculation logic taken from `ScoreProcessor`. should be updated here if the formula ever changes. if (!result.Type.IsScorable() || result.Type.IsBonus()) return false; - return scoreProcessor.Accuracy.Value < MinimumAccuracy.Value; + return getAccuracyWithImminentResultAdded(result) < MinimumAccuracy.Value; + } + + private double getAccuracyWithImminentResultAdded(JudgementResult result) + { + var score = new ScoreInfo { Ruleset = scoreProcessor.Ruleset.RulesetInfo }; + + // This is super ugly, but if we don't do it this way we will not have the most recent result added to the accuracy value. + // Hopefully we can improve this in the future. + scoreProcessor.PopulateScore(score); + score.Statistics[result.Type]++; + + return scoreProcessor.ComputeAccuracy(score); } } diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index ff0d91c0dd..3ff1b69612 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -97,7 +97,11 @@ namespace osu.Game.Rulesets.Scoring /// protected virtual double ClassicScoreMultiplier => 36; - private readonly Ruleset ruleset; + /// + /// The ruleset this score processor is valid for. + /// + public readonly Ruleset Ruleset; + private readonly double accuracyPortion; private readonly double comboPortion; @@ -145,7 +149,7 @@ namespace osu.Game.Rulesets.Scoring public ScoreProcessor(Ruleset ruleset) { - this.ruleset = ruleset; + this.Ruleset = ruleset; accuracyPortion = DefaultAccuracyPortion; comboPortion = DefaultComboPortion; @@ -291,8 +295,8 @@ namespace osu.Game.Rulesets.Scoring [Pure] public double ComputeAccuracy(ScoreInfo scoreInfo) { - if (!ruleset.RulesetInfo.Equals(scoreInfo.Ruleset)) - throw new ArgumentException($"Unexpected score ruleset. Expected \"{ruleset.RulesetInfo.ShortName}\" but was \"{scoreInfo.Ruleset.ShortName}\"."); + if (!Ruleset.RulesetInfo.Equals(scoreInfo.Ruleset)) + throw new ArgumentException($"Unexpected score ruleset. Expected \"{Ruleset.RulesetInfo.ShortName}\" but was \"{scoreInfo.Ruleset.ShortName}\"."); // We only extract scoring values from the score's statistics. This is because accuracy is always relative to the point of pass or fail rather than relative to the whole beatmap. extractScoringValues(scoreInfo.Statistics, out var current, out var maximum); @@ -312,8 +316,8 @@ namespace osu.Game.Rulesets.Scoring [Pure] public long ComputeScore(ScoringMode mode, ScoreInfo scoreInfo) { - if (!ruleset.RulesetInfo.Equals(scoreInfo.Ruleset)) - throw new ArgumentException($"Unexpected score ruleset. Expected \"{ruleset.RulesetInfo.ShortName}\" but was \"{scoreInfo.Ruleset.ShortName}\"."); + if (!Ruleset.RulesetInfo.Equals(scoreInfo.Ruleset)) + throw new ArgumentException($"Unexpected score ruleset. Expected \"{Ruleset.RulesetInfo.ShortName}\" but was \"{scoreInfo.Ruleset.ShortName}\"."); extractScoringValues(scoreInfo, out var current, out var maximum); @@ -552,7 +556,7 @@ namespace osu.Game.Rulesets.Scoring break; default: - maxResult = maxBasicResult ??= ruleset.GetHitResults().MaxBy(kvp => Judgement.ToNumericResult(kvp.result)).result; + maxResult = maxBasicResult ??= Ruleset.GetHitResults().MaxBy(kvp => Judgement.ToNumericResult(kvp.result)).result; break; } From 24ed84aad04b1e2c6d04375f5553e6061836f97d Mon Sep 17 00:00:00 2001 From: StanR Date: Wed, 18 Jan 2023 16:25:11 +0300 Subject: [PATCH 082/430] Add tiered level badge colouring --- .../Visual/Online/TestSceneLevelBadge.cs | 58 +++++++++++++++++++ osu.Game/Graphics/OsuColour.cs | 36 ++++++++++++ .../Profile/Header/Components/LevelBadge.cs | 39 +++++++++++-- osu.Game/Scoring/RankingTier.cs | 17 ++++++ 4 files changed, 146 insertions(+), 4 deletions(-) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneLevelBadge.cs create mode 100644 osu.Game/Scoring/RankingTier.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneLevelBadge.cs b/osu.Game.Tests/Visual/Online/TestSceneLevelBadge.cs new file mode 100644 index 0000000000..71c57896d2 --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneLevelBadge.cs @@ -0,0 +1,58 @@ +// 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.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Overlays.Profile.Header.Components; +using osu.Game.Users; +using osuTK; + +namespace osu.Game.Tests.Visual.Online +{ + [TestFixture] + public partial class TestSceneLevelBadge : OsuTestScene + { + public TestSceneLevelBadge() + { + var levels = new List(); + + for (int i = 0; i < 11; i++) + { + levels.Add(new UserStatistics.LevelInfo + { + Current = i * 10 + }); + } + + levels.Add(new UserStatistics.LevelInfo { Current = 101 }); + levels.Add(new UserStatistics.LevelInfo { Current = 105 }); + levels.Add(new UserStatistics.LevelInfo { Current = 110 }); + levels.Add(new UserStatistics.LevelInfo { Current = 115 }); + levels.Add(new UserStatistics.LevelInfo { Current = 120 }); + + Children = new Drawable[] + { + new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5), + ChildrenEnumerable = levels.Select(l => new LevelBadge + { + Size = new Vector2(60), + LevelInfo = { Value = l } + }) + } + }; + } + } +} diff --git a/osu.Game/Graphics/OsuColour.cs b/osu.Game/Graphics/OsuColour.cs index c5659aaf57..5e2649377a 100644 --- a/osu.Game/Graphics/OsuColour.cs +++ b/osu.Game/Graphics/OsuColour.cs @@ -5,6 +5,7 @@ using System; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics.Colour; using osu.Game.Beatmaps; using osu.Game.Online.Rooms; using osu.Game.Overlays; @@ -187,6 +188,41 @@ namespace osu.Game.Graphics } } + /// + /// Retrieves colour for a . + /// See https://www.figma.com/file/YHWhp9wZ089YXgB7pe6L1k/Tier-Colours + /// + public ColourInfo ForRankingTiers(RankingTier tier) + { + switch (tier) + { + default: + case RankingTier.Iron: + return Color4Extensions.FromHex(@"BAB3AB"); + + case RankingTier.Bronze: + return ColourInfo.GradientVertical(Color4Extensions.FromHex(@"B88F7A"), Color4Extensions.FromHex(@"855C47")); + + case RankingTier.Silver: + return ColourInfo.GradientVertical(Color4Extensions.FromHex(@"E0E0EB"), Color4Extensions.FromHex(@"A3A3C2")); + + case RankingTier.Gold: + return ColourInfo.GradientVertical(Color4Extensions.FromHex(@"F0E4A8"), Color4Extensions.FromHex(@"E0C952")); + + case RankingTier.Platinum: + return ColourInfo.GradientVertical(Color4Extensions.FromHex(@"A8F0EF"), Color4Extensions.FromHex(@"52E0DF")); + + case RankingTier.Rhodium: + return ColourInfo.GradientVertical(Color4Extensions.FromHex(@"D9F8D3"), Color4Extensions.FromHex(@"A0CF96")); + + case RankingTier.Radiant: + return ColourInfo.GradientVertical(Color4Extensions.FromHex(@"97DCFF"), Color4Extensions.FromHex(@"ED82FF")); + + case RankingTier.Lustrous: + return ColourInfo.GradientVertical(Color4Extensions.FromHex(@"FFE600"), Color4Extensions.FromHex(@"ED82FF")); + } + } + /// /// Returns a foreground text colour that is supposed to contrast well with /// the supplied . diff --git a/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs b/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs index 00bb8cbc75..ddc084a600 100644 --- a/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Sprites; @@ -12,6 +13,7 @@ using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Resources.Localisation.Web; +using osu.Game.Scoring; using osu.Game.Users; namespace osu.Game.Overlays.Profile.Header.Components @@ -23,6 +25,10 @@ namespace osu.Game.Overlays.Profile.Header.Components public LocalisableString TooltipText { get; private set; } private OsuSpriteText levelText = null!; + private Sprite sprite = null!; + + [Resolved] + private OsuColour osuColour { get; set; } = null!; public LevelBadge() { @@ -34,7 +40,7 @@ namespace osu.Game.Overlays.Profile.Header.Components { InternalChildren = new Drawable[] { - new Sprite + sprite = new Sprite { RelativeSizeAxes = Axes.Both, Texture = textures.Get("Profile/levelbadge"), @@ -58,9 +64,34 @@ namespace osu.Game.Overlays.Profile.Header.Components private void updateLevel(UserStatistics.LevelInfo? levelInfo) { - string level = levelInfo?.Current.ToString() ?? "0"; - levelText.Text = level; - TooltipText = UsersStrings.ShowStatsLevel(level); + int level = levelInfo?.Current ?? 0; + + levelText.Text = level.ToString(); + TooltipText = UsersStrings.ShowStatsLevel(level.ToString()); + + sprite.Colour = mapLevelToTierColour(level); + } + + private ColourInfo mapLevelToTierColour(int level) + { + var tier = RankingTier.Iron; + + if (level > 0) + { + tier = (RankingTier)(level / 20); + } + + if (level >= 105) + { + tier = RankingTier.Radiant; + } + + if (level >= 110) + { + tier = RankingTier.Lustrous; + } + + return osuColour.ForRankingTiers(tier); } } } diff --git a/osu.Game/Scoring/RankingTier.cs b/osu.Game/Scoring/RankingTier.cs new file mode 100644 index 0000000000..e57c241515 --- /dev/null +++ b/osu.Game/Scoring/RankingTier.cs @@ -0,0 +1,17 @@ +// 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.Scoring +{ + public enum RankingTier + { + Iron, + Bronze, + Silver, + Gold, + Platinum, + Rhodium, + Radiant, + Lustrous + } +} From 8ae82484b5ec550261366337eb5fcec04549495d Mon Sep 17 00:00:00 2001 From: StanR Date: Wed, 18 Jan 2023 16:38:58 +0300 Subject: [PATCH 083/430] Usings --- osu.Game.Tests/Visual/Online/TestSceneLevelBadge.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneLevelBadge.cs b/osu.Game.Tests/Visual/Online/TestSceneLevelBadge.cs index 71c57896d2..fef6dd0477 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneLevelBadge.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneLevelBadge.cs @@ -6,9 +6,6 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; using osu.Game.Overlays.Profile.Header.Components; using osu.Game.Users; using osuTK; From c9375c056e3444b4e0fe9730b31ee025ddf3aa95 Mon Sep 17 00:00:00 2001 From: Wleter Date: Wed, 18 Jan 2023 15:54:24 +0100 Subject: [PATCH 084/430] revert back name change --- .../Edit/Compose/Components/BlueprintContainer.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index c9d9f2266a..49e4ab5300 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -486,20 +486,20 @@ namespace osu.Game.Screens.Edit.Compose.Components Debug.Assert(movementBlueprintOriginalPositions != null); - Vector2 distanceTraveled = e.ScreenSpaceMousePosition - e.ScreenSpaceMouseDownPosition; + Vector2 distanceTravelled = e.ScreenSpaceMousePosition - e.ScreenSpaceMouseDownPosition; if (snapProvider != null) { var currentSelectionPointPositions = movementBlueprints.Select(m => m.ScreenSpaceSelectionPoint).ToArray(); - if (checkSnappingForNearbyObjects(distanceTraveled, movementBlueprintOriginalPositions, currentSelectionPointPositions)) + if (checkSnappingForNearbyObjects(distanceTravelled, movementBlueprintOriginalPositions, currentSelectionPointPositions)) return true; var currentEndPointPositions = movementBlueprints.Where(m => m.ScreenSpaceSelectionPoint != m.ScreenSpaceEndPoint) .Select(m => m.ScreenSpaceEndPoint) .ToArray(); - if (checkSnappingForNearbyObjects(distanceTraveled, movementBlueprintOriginalEndPositions, currentEndPointPositions)) + if (checkSnappingForNearbyObjects(distanceTravelled, movementBlueprintOriginalEndPositions, currentEndPointPositions)) return true; } @@ -507,7 +507,7 @@ namespace osu.Game.Screens.Edit.Compose.Components // item in the selection. // The final movement position, relative to movementBlueprintOriginalPosition. - Vector2 movePosition = movementBlueprintOriginalPositions.First() + distanceTraveled; + Vector2 movePosition = movementBlueprintOriginalPositions.First() + distanceTravelled; // Retrieve a snapped position. var result = snapProvider?.FindSnappedPositionAndTime(movePosition, ~SnapType.NearbyObjects); @@ -523,16 +523,16 @@ namespace osu.Game.Screens.Edit.Compose.Components /// /// Check for positional snap for every given positions. /// - /// Distance traveled since start of dragging action. + /// Distance traveled since start of dragging action. /// The position of objects before start of dragging action. /// The positions of object at the current time. /// Whether found object to snap to. - private bool checkSnappingForNearbyObjects(Vector2 distanceTraveled, Vector2[] originalPositions, Vector2[] currentPositions) + private bool checkSnappingForNearbyObjects(Vector2 distanceTravelled, Vector2[] originalPositions, Vector2[] currentPositions) { for (int i = 0; i < originalPositions.Length; i++) { Vector2 originalPosition = originalPositions[i]; - var testPosition = originalPosition + distanceTraveled; + var testPosition = originalPosition + distanceTravelled; var positionalResult = snapProvider.FindSnappedPositionAndTime(testPosition, SnapType.NearbyObjects); From e5eab72aeb493dd870c243c1d7fec184bc2f97e7 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Thu, 19 Jan 2023 00:37:36 +0900 Subject: [PATCH 085/430] add check for preview time setting --- osu.Game/Rulesets/Edit/BeatmapVerifier.cs | 3 + .../Rulesets/Edit/Checks/CheckPreviewTime.cs | 64 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 osu.Game/Rulesets/Edit/Checks/CheckPreviewTime.cs diff --git a/osu.Game/Rulesets/Edit/BeatmapVerifier.cs b/osu.Game/Rulesets/Edit/BeatmapVerifier.cs index a89a0e76a9..5f5aba26bb 100644 --- a/osu.Game/Rulesets/Edit/BeatmapVerifier.cs +++ b/osu.Game/Rulesets/Edit/BeatmapVerifier.cs @@ -36,6 +36,9 @@ namespace osu.Game.Rulesets.Edit new CheckUnsnappedObjects(), new CheckConcurrentObjects(), new CheckZeroLengthObjects(), + + // Timing + new CheckPreviewTime(), }; public IEnumerable Run(BeatmapVerifierContext context) diff --git a/osu.Game/Rulesets/Edit/Checks/CheckPreviewTime.cs b/osu.Game/Rulesets/Edit/Checks/CheckPreviewTime.cs new file mode 100644 index 0000000000..4fad8c0af6 --- /dev/null +++ b/osu.Game/Rulesets/Edit/Checks/CheckPreviewTime.cs @@ -0,0 +1,64 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Edit.Checks.Components; + +namespace osu.Game.Rulesets.Edit.Checks +{ + public class CheckPreviewTime : ICheck + { + public CheckMetadata Metadata => new CheckMetadata(CheckCategory.Timing, "Check Preview Time Consistency"); + + public IEnumerable PossibleTemplates => new IssueTemplate[] + { + new IssueTemplatePreviewTimeConflict(this), + new IssueTemplateHasNoPreviewTime(this), + }; + + public IEnumerable Run(BeatmapVerifierContext context) + { + var diffList = context.Beatmap.BeatmapInfo.BeatmapSet?.Beatmaps ?? new List(); + int previewTime = context.Beatmap.BeatmapInfo.Metadata.PreviewTime; + + if (previewTime == -1) + { + yield return new IssueTemplateHasNoPreviewTime(this).Create(); + } + + foreach (var diff in diffList) + { + if (diff.Equals(context.Beatmap.BeatmapInfo)) + { + continue; + } + + if (diff.Metadata.PreviewTime != previewTime) + { + yield return new IssueTemplatePreviewTimeConflict(this).Create(diff.DifficultyName); + } + } + } + + public class IssueTemplatePreviewTimeConflict : IssueTemplate + { + public IssueTemplatePreviewTimeConflict(ICheck check) + : base(check, IssueType.Warning, "Audio preview time conflicts with {0} diff") + { + } + + public Issue Create(string diffName) => new Issue(this, diffName); + } + + public class IssueTemplateHasNoPreviewTime : IssueTemplate + { + public IssueTemplateHasNoPreviewTime(ICheck check) + : base(check, IssueType.Warning, "A preview point for this map is not set. Consider settings one from the Timing menu") + { + } + + public Issue Create() => new Issue(this); + } + } +} From 997a1a8b02d0b99ba77a4dbe629ea5f2d8f46a9f Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Thu, 19 Jan 2023 01:00:02 +0900 Subject: [PATCH 086/430] add test for CheckPreviewTime --- .../Editing/Checks/CheckPreviewTimeTest.cs | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 osu.Game.Tests/Editing/Checks/CheckPreviewTimeTest.cs diff --git a/osu.Game.Tests/Editing/Checks/CheckPreviewTimeTest.cs b/osu.Game.Tests/Editing/Checks/CheckPreviewTimeTest.cs new file mode 100644 index 0000000000..59ff8d4923 --- /dev/null +++ b/osu.Game.Tests/Editing/Checks/CheckPreviewTimeTest.cs @@ -0,0 +1,108 @@ +// 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.Game.Beatmaps; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Edit.Checks; +using osu.Game.Rulesets.Objects; +using osu.Game.Tests.Beatmaps; + +namespace osu.Game.Tests.Editing.Checks +{ + public class CheckPreviewTimeTest + { + private CheckPreviewTime check = null!; + + private IBeatmap beatmap = null!; + + [SetUp] + public void Setup() + { + check = new CheckPreviewTime(); + beatmap = new Beatmap + { + BeatmapInfo = new BeatmapInfo + { + Metadata = new BeatmapMetadata { PreviewTime = -1 }, + BeatmapSet = new BeatmapSetInfo(new List + { + new BeatmapInfo + { + DifficultyName = "Test1", + Metadata = new BeatmapMetadata { PreviewTime = 5 }, + }, + new BeatmapInfo + { + DifficultyName = "Test2", + Metadata = new BeatmapMetadata { PreviewTime = 10 }, + }, + }) + } + }; + } + + [Test] + public void TestPreviewTimeNotSet() + { + setNoPreviewTimeBeatmap(); + var content = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap)); + + var issues = check.Run(content).ToList(); + + Assert.That(issues, Has.Count.EqualTo(1)); + Assert.That(issues.Single().Template is CheckPreviewTime.IssueTemplateHasNoPreviewTime); + } + + [Test] + public void TestPreviewTimeconflict() + { + setPreviewTimeConflictBeatmap(); + + var content = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap)); + + var issues = check.Run(content).ToList(); + + Assert.That(issues, Has.Count.EqualTo(1)); + Assert.That(issues.Single().Template is CheckPreviewTime.IssueTemplatePreviewTimeConflict); + Assert.That(issues.Single().Arguments.Single().ToString() == "Test1"); + } + + private void setNoPreviewTimeBeatmap() + { + beatmap = new Beatmap + { + BeatmapInfo = new BeatmapInfo + { + Metadata = new BeatmapMetadata { PreviewTime = -1 }, + } + }; + } + + private void setPreviewTimeConflictBeatmap() + { + beatmap = new Beatmap + { + BeatmapInfo = new BeatmapInfo + { + Metadata = new BeatmapMetadata { PreviewTime = 10 }, + BeatmapSet = new BeatmapSetInfo(new List + { + new BeatmapInfo + { + DifficultyName = "Test1", + Metadata = new BeatmapMetadata { PreviewTime = 5 }, + }, + new BeatmapInfo + { + DifficultyName = "Test2", + Metadata = new BeatmapMetadata { PreviewTime = 10 }, + }, + }) + } + }; + } + } +} From e0f3fa1af61734545767fac51baa9ff7a1fb1838 Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Wed, 18 Jan 2023 12:22:27 -0500 Subject: [PATCH 087/430] remove `this` in ruleset assignment --- 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 3ff1b69612..b5f42ec2cc 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -149,7 +149,7 @@ namespace osu.Game.Rulesets.Scoring public ScoreProcessor(Ruleset ruleset) { - this.Ruleset = ruleset; + Ruleset = ruleset; accuracyPortion = DefaultAccuracyPortion; comboPortion = DefaultComboPortion; From 150195b8878bd9ca5ed83fe71f92487e92b52403 Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Wed, 18 Jan 2023 12:24:41 -0500 Subject: [PATCH 088/430] use extension method to check accuracy impact --- osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs index 02d4fb4d67..e18164db89 100644 --- a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs +++ b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs @@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Mods protected override bool FailCondition(HealthProcessor healthProcessor, JudgementResult result) { - if (!result.Type.IsScorable() || result.Type.IsBonus()) + if (!result.Type.AffectsAccuracy()) return false; return getAccuracyWithImminentResultAdded(result) < MinimumAccuracy.Value; From ab78dd0436edd06dba957b54634b30c6ad57807c Mon Sep 17 00:00:00 2001 From: Wleter Date: Wed, 18 Jan 2023 21:34:23 +0100 Subject: [PATCH 089/430] add collection of selection points. --- .../Sliders/SliderSelectionBlueprint.cs | 8 +++- .../Edit/HitObjectSelectionBlueprint.cs | 2 - osu.Game/Rulesets/Edit/SelectionBlueprint.cs | 8 ++-- .../Compose/Components/BlueprintContainer.cs | 41 ++++++++----------- 4 files changed, 28 insertions(+), 31 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 634897e3d5..66adcd62a6 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -409,8 +409,12 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders public override Vector2 ScreenSpaceSelectionPoint => DrawableObject.SliderBody?.ToScreenSpace(DrawableObject.SliderBody.PathOffset) ?? BodyPiece.ToScreenSpace(BodyPiece.PathStartLocation); - public override Vector2 ScreenSpaceEndPoint => DrawableObject.SliderBody?.ToScreenSpace(DrawableObject.SliderBody.PathEndOffset) - ?? BodyPiece.ToScreenSpace(BodyPiece.PathEndLocation); + public override Vector2[] ScreenSpaceSelectionPoints => new Vector2[] + { + ScreenSpaceSelectionPoint, + DrawableObject.SliderBody?.ToScreenSpace(DrawableObject.SliderBody.PathEndOffset) + ?? BodyPiece.ToScreenSpace(BodyPiece.PathEndLocation) + }; public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => BodyPiece.ReceivePositionalInputAt(screenSpacePos) || ControlPointVisualiser?.Pieces.Any(p => p.ReceivePositionalInputAt(screenSpacePos)) == true; diff --git a/osu.Game/Rulesets/Edit/HitObjectSelectionBlueprint.cs b/osu.Game/Rulesets/Edit/HitObjectSelectionBlueprint.cs index 3aa086582f..93b889792b 100644 --- a/osu.Game/Rulesets/Edit/HitObjectSelectionBlueprint.cs +++ b/osu.Game/Rulesets/Edit/HitObjectSelectionBlueprint.cs @@ -48,8 +48,6 @@ namespace osu.Game.Rulesets.Edit public override Vector2 ScreenSpaceSelectionPoint => DrawableObject.ScreenSpaceDrawQuad.Centre; - public override Vector2 ScreenSpaceEndPoint => DrawableObject.ScreenSpaceDrawQuad.Centre; - public override Quad SelectionQuad => DrawableObject.ScreenSpaceDrawQuad; } diff --git a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs index a27a59be34..3b86dbbe81 100644 --- a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs +++ b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using System.Collections.Generic; using osu.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -125,14 +126,15 @@ namespace osu.Game.Rulesets.Edit public virtual MenuItem[] ContextMenuItems => Array.Empty(); /// - /// The screen-space point that causes this to be selected via a drag. + /// The screen-space main point that causes this to be selected via a drag. /// public virtual Vector2 ScreenSpaceSelectionPoint => ScreenSpaceDrawQuad.Centre; /// - /// The screen-space point that mark end of this . + /// The screen-space collection of base points that cause this to be selected via a drag. + /// The first element of this collection is /// - public virtual Vector2 ScreenSpaceEndPoint => ScreenSpaceDrawQuad.Centre; + public virtual Vector2[] ScreenSpaceSelectionPoints => new Vector2[] { ScreenSpaceSelectionPoint }; /// /// The screen-space quad that outlines this for selections. diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index 49e4ab5300..750b7697b8 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -439,8 +439,7 @@ namespace osu.Game.Screens.Edit.Compose.Components #region Selection Movement - private Vector2[] movementBlueprintOriginalPositions; - private Vector2[] movementBlueprintOriginalEndPositions; + private Vector2[][] movementBlueprintsOriginalPositions; private SelectionBlueprint[] movementBlueprints; private bool isDraggingBlueprint; @@ -460,9 +459,7 @@ namespace osu.Game.Screens.Edit.Compose.Components // Movement is tracked from the blueprint of the earliest item, since it only makes sense to distance snap from that item movementBlueprints = SortForMovement(SelectionHandler.SelectedBlueprints).ToArray(); - movementBlueprintOriginalPositions = movementBlueprints.Select(m => m.ScreenSpaceSelectionPoint).ToArray(); - movementBlueprintOriginalEndPositions = movementBlueprints.Where(m => m.ScreenSpaceSelectionPoint != m.ScreenSpaceEndPoint) - .Select(m => m.ScreenSpaceEndPoint).ToArray(); + movementBlueprintsOriginalPositions = movementBlueprints.Select(m => m.ScreenSpaceSelectionPoints).ToArray(); return true; } @@ -484,30 +481,24 @@ namespace osu.Game.Screens.Edit.Compose.Components if (movementBlueprints == null) return false; - Debug.Assert(movementBlueprintOriginalPositions != null); + Debug.Assert(movementBlueprintsOriginalPositions != null); Vector2 distanceTravelled = e.ScreenSpaceMousePosition - e.ScreenSpaceMouseDownPosition; if (snapProvider != null) { - var currentSelectionPointPositions = movementBlueprints.Select(m => m.ScreenSpaceSelectionPoint).ToArray(); - - if (checkSnappingForNearbyObjects(distanceTravelled, movementBlueprintOriginalPositions, currentSelectionPointPositions)) - return true; - - var currentEndPointPositions = movementBlueprints.Where(m => m.ScreenSpaceSelectionPoint != m.ScreenSpaceEndPoint) - .Select(m => m.ScreenSpaceEndPoint) - .ToArray(); - - if (checkSnappingForNearbyObjects(distanceTravelled, movementBlueprintOriginalEndPositions, currentEndPointPositions)) - return true; + for (int i = 0; i < movementBlueprints.Length; i++) + { + if (checkSnappingBlueprintToNearbyObjects(movementBlueprints[i], distanceTravelled, movementBlueprintsOriginalPositions[i])) + return true; + } } // if no positional snapping could be performed, try unrestricted snapping from the earliest // item in the selection. // The final movement position, relative to movementBlueprintOriginalPosition. - Vector2 movePosition = movementBlueprintOriginalPositions.First() + distanceTravelled; + Vector2 movePosition = movementBlueprintsOriginalPositions.First().First() + distanceTravelled; // Retrieve a snapped position. var result = snapProvider?.FindSnappedPositionAndTime(movePosition, ~SnapType.NearbyObjects); @@ -521,14 +512,16 @@ namespace osu.Game.Screens.Edit.Compose.Components } /// - /// Check for positional snap for every given positions. + /// Check for positional snap for given blueprint. /// + /// The blueprint to check for snapping /// Distance traveled since start of dragging action. - /// The position of objects before start of dragging action. - /// The positions of object at the current time. + /// The selection positions of blueprint before start of dragging action. /// Whether found object to snap to. - private bool checkSnappingForNearbyObjects(Vector2 distanceTravelled, Vector2[] originalPositions, Vector2[] currentPositions) + private bool checkSnappingBlueprintToNearbyObjects(SelectionBlueprint blueprint, Vector2 distanceTravelled, Vector2[] originalPositions) { + var currentPositions = blueprint.ScreenSpaceSelectionPoints; + for (int i = 0; i < originalPositions.Length; i++) { Vector2 originalPosition = originalPositions[i]; @@ -541,7 +534,7 @@ namespace osu.Game.Screens.Edit.Compose.Components var delta = positionalResult.ScreenSpacePosition - currentPositions[i]; // attempt to move the objects, and abort any time based snapping if we can. - if (SelectionHandler.HandleMovement(new MoveSelectionEvent(movementBlueprints[i], delta))) + if (SelectionHandler.HandleMovement(new MoveSelectionEvent(blueprint, delta))) return true; } @@ -560,7 +553,7 @@ namespace osu.Game.Screens.Edit.Compose.Components if (movementBlueprints == null) return false; - movementBlueprintOriginalPositions = null; + movementBlueprintsOriginalPositions = null; movementBlueprints = null; return true; From 40e99069fcbd31174aefbffb03209a247cce5139 Mon Sep 17 00:00:00 2001 From: Wleter Date: Wed, 18 Jan 2023 21:43:09 +0100 Subject: [PATCH 090/430] fix typos and newlines --- .../Screens/Edit/Compose/Components/BlueprintContainer.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index 750b7697b8..40aa92a53f 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -460,7 +460,6 @@ namespace osu.Game.Screens.Edit.Compose.Components // Movement is tracked from the blueprint of the earliest item, since it only makes sense to distance snap from that item movementBlueprints = SortForMovement(SelectionHandler.SelectedBlueprints).ToArray(); movementBlueprintsOriginalPositions = movementBlueprints.Select(m => m.ScreenSpaceSelectionPoints).ToArray(); - return true; } @@ -515,7 +514,7 @@ namespace osu.Game.Screens.Edit.Compose.Components /// Check for positional snap for given blueprint. /// /// The blueprint to check for snapping - /// Distance traveled since start of dragging action. + /// Distance travelled since start of dragging action. /// The selection positions of blueprint before start of dragging action. /// Whether found object to snap to. private bool checkSnappingBlueprintToNearbyObjects(SelectionBlueprint blueprint, Vector2 distanceTravelled, Vector2[] originalPositions) @@ -537,7 +536,7 @@ namespace osu.Game.Screens.Edit.Compose.Components if (SelectionHandler.HandleMovement(new MoveSelectionEvent(blueprint, delta))) return true; } - + return false; } From f8d8a627b8d5c75d6fdb2417166be0c537afc731 Mon Sep 17 00:00:00 2001 From: Wleter Date: Wed, 18 Jan 2023 22:00:39 +0100 Subject: [PATCH 091/430] change property name --- .../Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs | 2 +- osu.Game/Rulesets/Edit/SelectionBlueprint.cs | 2 +- .../Screens/Edit/Compose/Components/BlueprintContainer.cs | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 66adcd62a6..660976ba33 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -409,7 +409,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders public override Vector2 ScreenSpaceSelectionPoint => DrawableObject.SliderBody?.ToScreenSpace(DrawableObject.SliderBody.PathOffset) ?? BodyPiece.ToScreenSpace(BodyPiece.PathStartLocation); - public override Vector2[] ScreenSpaceSelectionPoints => new Vector2[] + public override Vector2[] ScreenSpaceSnapPoints => new Vector2[] { ScreenSpaceSelectionPoint, DrawableObject.SliderBody?.ToScreenSpace(DrawableObject.SliderBody.PathEndOffset) diff --git a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs index 3b86dbbe81..b2f2fa8a9b 100644 --- a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs +++ b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs @@ -134,7 +134,7 @@ namespace osu.Game.Rulesets.Edit /// The screen-space collection of base points that cause this to be selected via a drag. /// The first element of this collection is /// - public virtual Vector2[] ScreenSpaceSelectionPoints => new Vector2[] { ScreenSpaceSelectionPoint }; + public virtual Vector2[] ScreenSpaceSnapPoints => new Vector2[] { ScreenSpaceSelectionPoint }; /// /// The screen-space quad that outlines this for selections. diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index 40aa92a53f..8cb5a1face 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -459,7 +459,7 @@ namespace osu.Game.Screens.Edit.Compose.Components // Movement is tracked from the blueprint of the earliest item, since it only makes sense to distance snap from that item movementBlueprints = SortForMovement(SelectionHandler.SelectedBlueprints).ToArray(); - movementBlueprintsOriginalPositions = movementBlueprints.Select(m => m.ScreenSpaceSelectionPoints).ToArray(); + movementBlueprintsOriginalPositions = movementBlueprints.Select(m => m.ScreenSpaceSnapPoints).ToArray(); return true; } @@ -519,7 +519,7 @@ namespace osu.Game.Screens.Edit.Compose.Components /// Whether found object to snap to. private bool checkSnappingBlueprintToNearbyObjects(SelectionBlueprint blueprint, Vector2 distanceTravelled, Vector2[] originalPositions) { - var currentPositions = blueprint.ScreenSpaceSelectionPoints; + var currentPositions = blueprint.ScreenSpaceSnapPoints; for (int i = 0; i < originalPositions.Length; i++) { @@ -536,7 +536,7 @@ namespace osu.Game.Screens.Edit.Compose.Components if (SelectionHandler.HandleMovement(new MoveSelectionEvent(blueprint, delta))) return true; } - + return false; } From 11e1b22bf5be695bebc5dad23ea9c2aa268d4be7 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Thu, 19 Jan 2023 20:53:35 +0900 Subject: [PATCH 092/430] 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 093/430] 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 a1b5c9d910593cff6d7b6c903eacf632a60ec0b0 Mon Sep 17 00:00:00 2001 From: naoey Date: Sun, 22 Jan 2023 01:10:14 +0900 Subject: [PATCH 094/430] Don't transfer MD5 hashes in collections when copying beatmaps Fixes #22306. Changes beatmap saving so that by default it does not transfer the hashes in collections, and only transfers them when saving the same difficulty in the editor. Issue seems to have been introduced in https://github.com/ppy/osu/pull/20641. --- .../Editing/TestSceneEditorBeatmapCreation.cs | 57 ++++++++++++++++++- osu.Game/Beatmaps/BeatmapManager.cs | 11 +++- osu.Game/Screens/Edit/Editor.cs | 2 +- osu.Game/Tests/Visual/EditorTestScene.cs | 2 +- 4 files changed, 66 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs index 3f89bf9e9c..5aa2dd2ebf 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs @@ -13,6 +13,7 @@ using osu.Framework.Screens; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Collections; using osu.Game.Database; using osu.Game.Overlays.Dialog; using osu.Game.Rulesets; @@ -42,6 +43,9 @@ namespace osu.Game.Tests.Visual.Editing [Resolved] private BeatmapManager beatmapManager { get; set; } = null!; + [Resolved] + private RealmAccess realm { get; set; } = null!; + private Guid currentBeatmapSetID => EditorBeatmap.BeatmapInfo.BeatmapSet?.ID ?? Guid.Empty; public override void SetUpSteps() @@ -224,7 +228,8 @@ namespace osu.Game.Tests.Visual.Editing return beatmap != null && beatmap.DifficultyName == secondDifficultyName && set != null - && set.PerformRead(s => s.Beatmaps.Count == 2 && s.Beatmaps.Any(b => b.DifficultyName == secondDifficultyName) && s.Beatmaps.All(b => s.Status == BeatmapOnlineStatus.LocallyModified)); + && set.PerformRead(s => + s.Beatmaps.Count == 2 && s.Beatmaps.Any(b => b.DifficultyName == secondDifficultyName) && s.Beatmaps.All(b => s.Status == BeatmapOnlineStatus.LocallyModified)); }); } @@ -327,6 +332,56 @@ namespace osu.Game.Tests.Visual.Editing AddAssert("old beatmap file not deleted", () => refetchedBeatmapSet.AsNonNull().PerformRead(s => s.Files.Count == 2)); } + [Test] + public void TestCopyDifficultyDoesNotChangeCollections() + { + string originalDifficultyName = Guid.NewGuid().ToString(); + + AddStep("set unique difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = originalDifficultyName); + AddStep("save beatmap", () => Editor.Save()); + + string originalMd5 = string.Empty; + BeatmapCollection collection = null!; + + AddStep("setup a collection with original beatmap", () => + { + collection = new BeatmapCollection("test copy"); + collection.BeatmapMD5Hashes.Add(originalMd5 = EditorBeatmap.BeatmapInfo.MD5Hash); + + realm.Write(r => + { + r.Add(collection); + }); + }); + + AddAssert("collection contains original beatmap", () => + !string.IsNullOrEmpty(originalMd5) && collection.BeatmapMD5Hashes.Contains(originalMd5)); + + AddStep("create new difficulty", () => Editor.CreateNewDifficulty(new OsuRuleset().RulesetInfo)); + + AddUntilStep("wait for dialog", () => DialogOverlay.CurrentDialog is CreateNewDifficultyDialog); + AddStep("confirm creation as a copy", () => DialogOverlay.CurrentDialog.Buttons.ElementAt(1).TriggerClick()); + + AddUntilStep("wait for created", () => + { + string? difficultyName = Editor.ChildrenOfType().SingleOrDefault()?.BeatmapInfo.DifficultyName; + return difficultyName != null && difficultyName != originalDifficultyName; + }); + + AddStep("save without changes", () => Editor.Save()); + + AddAssert("collection still points to old beatmap", () => !collection.BeatmapMD5Hashes.Contains(EditorBeatmap.BeatmapInfo.MD5Hash) + && collection.BeatmapMD5Hashes.Contains(originalMd5)); + + AddStep("clean up collection", () => + { + realm.Write(r => + { + r.Remove(collection); + }); + }); + } + [Test] public void TestCreateMultipleNewDifficultiesSucceeds() { diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 34637501fa..db9c450bbe 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -186,7 +186,10 @@ namespace osu.Game.Beatmaps targetBeatmapSet.Beatmaps.Add(newBeatmap.BeatmapInfo); newBeatmap.BeatmapInfo.BeatmapSet = targetBeatmapSet; - Save(newBeatmap.BeatmapInfo, newBeatmap, beatmapSkin); + // make sure that collections don't get transferred when adding new difficulties to a set (that function + // was added for the scenario of saving the same difficulty), since this path is invoked from copying + // an existing difficulty as well. + Save(newBeatmap.BeatmapInfo, newBeatmap, beatmapSkin, false); workingBeatmapCache.Invalidate(targetBeatmapSet); return GetWorkingBeatmap(newBeatmap.BeatmapInfo); @@ -285,7 +288,8 @@ namespace osu.Game.Beatmaps /// The to save the content against. The file referenced by will be replaced. /// The content to write. /// The beatmap content to write, null if to be omitted. - public virtual void Save(BeatmapInfo beatmapInfo, IBeatmap beatmapContent, ISkin? beatmapSkin = null) + /// Whether to transfer the MD5 hashes in collections referencing this beatmap. + public virtual void Save(BeatmapInfo beatmapInfo, IBeatmap beatmapContent, ISkin? beatmapSkin = null, bool transferCollections = false) { var setInfo = beatmapInfo.BeatmapSet; Debug.Assert(setInfo != null); @@ -337,7 +341,8 @@ namespace osu.Game.Beatmaps setInfo.CopyChangesToRealm(liveBeatmapSet); - beatmapInfo.TransferCollectionReferences(r, oldMd5Hash); + if (transferCollections) + beatmapInfo.TransferCollectionReferences(r, oldMd5Hash); ProcessBeatmap?.Invoke((liveBeatmapSet, false)); }); diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 74ea933255..7161f34df2 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -429,7 +429,7 @@ namespace osu.Game.Screens.Edit try { // save the loaded beatmap's data stream. - beatmapManager.Save(editorBeatmap.BeatmapInfo, editorBeatmap.PlayableBeatmap, editorBeatmap.BeatmapSkin); + beatmapManager.Save(editorBeatmap.BeatmapInfo, editorBeatmap.PlayableBeatmap, editorBeatmap.BeatmapSkin, true); } catch (Exception ex) { diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index 6e2f1e99cd..e9d186fe35 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -178,7 +178,7 @@ namespace osu.Game.Tests.Visual => testBeatmapManager.TestBeatmap; } - public override void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) + public override void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null, bool transferCollections = false) { // don't actually care about saving for this context. } From d4e5d7a8735bcb41792f77edf5a2a4fbdcda5c0c Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Sat, 21 Jan 2023 22:29:28 +0100 Subject: [PATCH 095/430] Move fixed scroll speed change out of classic mod for taiko --- .../Mods/TaikoModClassic.cs | 20 ++----------------- .../UI/DrawableTaikoRuleset.cs | 14 ++++++++++++- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs index 3b3b3e606c..2ccdfd40e5 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Diagnostics; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.UI; @@ -9,30 +8,15 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Taiko.Mods { - public class TaikoModClassic : ModClassic, IApplicableToDrawableRuleset, IUpdatableByPlayfield + public class TaikoModClassic : ModClassic, IApplicableToDrawableRuleset { - private DrawableTaikoRuleset? drawableTaikoRuleset; - public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { - drawableTaikoRuleset = (DrawableTaikoRuleset)drawableRuleset; + var drawableTaikoRuleset = (DrawableTaikoRuleset)drawableRuleset; drawableTaikoRuleset.LockPlayfieldMaxAspect.Value = false; var playfield = (TaikoPlayfield)drawableRuleset.Playfield; playfield.ClassicHitTargetPosition.Value = true; } - - public void Update(Playfield playfield) - { - Debug.Assert(drawableTaikoRuleset != null); - - // Classic taiko scrolls at a constant 100px per 1000ms. More notes become visible as the playfield is lengthened. - const float scroll_rate = 10; - - // Since the time range will depend on a positional value, it is referenced to the x480 pixel space. - float ratio = drawableTaikoRuleset.DrawHeight / 480; - - drawableTaikoRuleset.TimeRange.Value = (playfield.HitObjectContainer.DrawWidth / ratio) * scroll_rate; - } } } diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs index 146daa8c27..40203440c5 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs @@ -43,7 +43,6 @@ namespace osu.Game.Rulesets.Taiko.UI : base(ruleset, beatmap, mods) { Direction.Value = ScrollingDirection.Left; - TimeRange.Value = 7000; } [BackgroundDependencyLoader] @@ -60,6 +59,19 @@ namespace osu.Game.Rulesets.Taiko.UI KeyBindingInputManager.Add(new DrumTouchInputArea()); } + protected override void Update() + { + base.Update(); + + // Taiko scrolls at a constant 100px per 1000ms. More notes become visible as the playfield is lengthened. + const float scroll_rate = 10; + + // Since the time range will depend on a positional value, it is referenced to the x480 pixel space. + float ratio = DrawHeight / 480; + + TimeRange.Value = (Playfield.HitObjectContainer.DrawWidth / ratio) * scroll_rate; + } + protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); From 718cbf9382a20351dc4fc127b91e63f1331dd19d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 21 Jan 2023 23:19:34 +0100 Subject: [PATCH 096/430] Fix `SegmentedGraph` draw node calculating segment colours in unsafe manner The `SegmentedGraph`'s draw node would call `getSegmentColour()` on the drawable, which would query the `DrawColourInfo` and `tierColours` properties of the drawable. This is a cross-thread access and as such completely unsafe, as due to being cross-thread it can die on invalidations or out-of-bounds accesses. Fix by transferring everything to the draw node first before attempting to draw. `SegmentedGraph.TierColours` setter already correctly invalidates the draw node via `graphNeedsUpdate`, so no further intervention was required there. Closes #22326. --- .../Graphics/UserInterface/SegmentedGraph.cs | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/SegmentedGraph.cs b/osu.Game/Graphics/UserInterface/SegmentedGraph.cs index 6ca0c588e8..e8817d5275 100644 --- a/osu.Game/Graphics/UserInterface/SegmentedGraph.cs +++ b/osu.Game/Graphics/UserInterface/SegmentedGraph.cs @@ -152,22 +152,6 @@ namespace osu.Game.Graphics.UserInterface segments.Sort(); } - private ColourInfo getSegmentColour(SegmentInfo segment) - { - var segmentColour = new ColourInfo - { - TopLeft = DrawColourInfo.Colour.Interpolate(new Vector2(segment.Start, 0f)), - TopRight = DrawColourInfo.Colour.Interpolate(new Vector2(segment.End, 0f)), - BottomLeft = DrawColourInfo.Colour.Interpolate(new Vector2(segment.Start, 1f)), - BottomRight = DrawColourInfo.Colour.Interpolate(new Vector2(segment.End, 1f)) - }; - - var tierColour = segment.Tier >= 0 ? tierColours[segment.Tier] : new Colour4(0, 0, 0, 0); - segmentColour.ApplyChild(tierColour); - - return segmentColour; - } - protected override DrawNode CreateDrawNode() => new SegmentedGraphDrawNode(this); protected struct SegmentInfo @@ -215,6 +199,7 @@ namespace osu.Game.Graphics.UserInterface private IShader shader = null!; private readonly List segments = new List(); private Vector2 drawSize; + private readonly List tierColours = new List(); public SegmentedGraphDrawNode(SegmentedGraph source) : base(source) @@ -228,8 +213,12 @@ namespace osu.Game.Graphics.UserInterface texture = Source.texture; shader = Source.shader; drawSize = Source.DrawSize; + segments.Clear(); segments.AddRange(Source.segments.Where(s => s.Length * drawSize.X > 1)); + + tierColours.Clear(); + tierColours.AddRange(Source.tierColours); } public override void Draw(IRenderer renderer) @@ -252,11 +241,27 @@ namespace osu.Game.Graphics.UserInterface Vector2Extensions.Transform(topRight, DrawInfo.Matrix), Vector2Extensions.Transform(bottomLeft, DrawInfo.Matrix), Vector2Extensions.Transform(bottomRight, DrawInfo.Matrix)), - Source.getSegmentColour(segment)); + getSegmentColour(segment)); } shader.Unbind(); } + + private ColourInfo getSegmentColour(SegmentInfo segment) + { + var segmentColour = new ColourInfo + { + TopLeft = DrawColourInfo.Colour.Interpolate(new Vector2(segment.Start, 0f)), + TopRight = DrawColourInfo.Colour.Interpolate(new Vector2(segment.End, 0f)), + BottomLeft = DrawColourInfo.Colour.Interpolate(new Vector2(segment.Start, 1f)), + BottomRight = DrawColourInfo.Colour.Interpolate(new Vector2(segment.End, 1f)) + }; + + var tierColour = segment.Tier >= 0 ? tierColours[segment.Tier] : new Colour4(0, 0, 0, 0); + segmentColour.ApplyChild(tierColour); + + return segmentColour; + } } protected class SegmentManager : IEnumerable From 1c1c9915bb259d0021cd3e597609f714004594f8 Mon Sep 17 00:00:00 2001 From: naoey Date: Sun, 22 Jan 2023 10:27:33 +0900 Subject: [PATCH 097/430] Split saving new and existing beatmaps into separate flows --- .../Beatmaps/WorkingBeatmapManagerTest.cs | 2 +- osu.Game/Beatmaps/BeatmapManager.cs | 148 ++++++++++-------- osu.Game/Screens/Edit/Editor.cs | 5 +- osu.Game/Tests/Visual/EditorTestScene.cs | 7 +- 4 files changed, 91 insertions(+), 71 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs b/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs index 89b8c8927d..4cd866392b 100644 --- a/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs +++ b/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs @@ -124,7 +124,7 @@ namespace osu.Game.Tests.Beatmaps Assert.That(preserveCollection.BeatmapMD5Hashes, Does.Contain(initialHash)); Assert.That(noNewCollection.BeatmapMD5Hashes, Does.Not.Contain(initialHash)); - beatmaps.Save(working.BeatmapInfo, working.GetPlayableBeatmap(new OsuRuleset().RulesetInfo)); + beatmaps.SaveExistingBeatmap(working.BeatmapInfo, working.GetPlayableBeatmap(new OsuRuleset().RulesetInfo)); string finalHash = working.BeatmapInfo.MD5Hash; diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index db9c450bbe..d644031fe1 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -186,10 +186,7 @@ namespace osu.Game.Beatmaps targetBeatmapSet.Beatmaps.Add(newBeatmap.BeatmapInfo); newBeatmap.BeatmapInfo.BeatmapSet = targetBeatmapSet; - // make sure that collections don't get transferred when adding new difficulties to a set (that function - // was added for the scenario of saving the same difficulty), since this path is invoked from copying - // an existing difficulty as well. - Save(newBeatmap.BeatmapInfo, newBeatmap, beatmapSkin, false); + SaveNewBeatmap(newBeatmap.BeatmapInfo, newBeatmap, beatmapSkin); workingBeatmapCache.Invalidate(targetBeatmapSet); return GetWorkingBeatmap(newBeatmap.BeatmapInfo); @@ -283,78 +280,30 @@ namespace osu.Game.Beatmaps public IWorkingBeatmap DefaultBeatmap => workingBeatmapCache.DefaultBeatmap; /// - /// Saves an file against a given . + /// Saves an existing file against a given , also transferring the beatmap + /// hashes in any collections referencing it. /// /// The to save the content against. The file referenced by will be replaced. /// The content to write. /// The beatmap content to write, null if to be omitted. - /// Whether to transfer the MD5 hashes in collections referencing this beatmap. - public virtual void Save(BeatmapInfo beatmapInfo, IBeatmap beatmapContent, ISkin? beatmapSkin = null, bool transferCollections = false) + public virtual void SaveExistingBeatmap(BeatmapInfo beatmapInfo, IBeatmap beatmapContent, ISkin? beatmapSkin = null) { - var setInfo = beatmapInfo.BeatmapSet; - Debug.Assert(setInfo != null); + string oldMd5Hash = beatmapInfo.MD5Hash; - // Difficulty settings must be copied first due to the clone in `Beatmap<>.BeatmapInfo_Set`. - // This should hopefully be temporary, assuming said clone is eventually removed. + save(beatmapInfo, beatmapContent, beatmapSkin); - // Warning: The directionality here is important. Changes have to be copied *from* beatmapContent (which comes from editor and is being saved) - // *to* the beatmapInfo (which is a database model and needs to receive values without the taiko slider velocity multiplier for correct operation). - // CopyTo() will undo such adjustments, while CopyFrom() will not. - beatmapContent.Difficulty.CopyTo(beatmapInfo.Difficulty); + Realm.Write(r => beatmapInfo.TransferCollectionReferences(r, oldMd5Hash)); + } - // All changes to metadata are made in the provided beatmapInfo, so this should be copied to the `IBeatmap` before encoding. - beatmapContent.BeatmapInfo = beatmapInfo; - - using (var stream = new MemoryStream()) - { - using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true)) - new LegacyBeatmapEncoder(beatmapContent, beatmapSkin).Encode(sw); - - stream.Seek(0, SeekOrigin.Begin); - - // AddFile generally handles updating/replacing files, but this is a case where the filename may have also changed so let's delete for simplicity. - var existingFileInfo = beatmapInfo.Path != null ? setInfo.GetFile(beatmapInfo.Path) : null; - string targetFilename = createBeatmapFilenameFromMetadata(beatmapInfo); - - // ensure that two difficulties from the set don't point at the same beatmap file. - if (setInfo.Beatmaps.Any(b => b.ID != beatmapInfo.ID && string.Equals(b.Path, targetFilename, StringComparison.OrdinalIgnoreCase))) - throw new InvalidOperationException($"{setInfo.GetDisplayString()} already has a difficulty with the name of '{beatmapInfo.DifficultyName}'."); - - if (existingFileInfo != null) - DeleteFile(setInfo, existingFileInfo); - - string oldMd5Hash = beatmapInfo.MD5Hash; - - beatmapInfo.MD5Hash = stream.ComputeMD5Hash(); - beatmapInfo.Hash = stream.ComputeSHA2Hash(); - - beatmapInfo.LastLocalUpdate = DateTimeOffset.Now; - beatmapInfo.Status = BeatmapOnlineStatus.LocallyModified; - - AddFile(setInfo, stream, createBeatmapFilenameFromMetadata(beatmapInfo)); - - updateHashAndMarkDirty(setInfo); - - Realm.Write(r => - { - var liveBeatmapSet = r.Find(setInfo.ID); - - setInfo.CopyChangesToRealm(liveBeatmapSet); - - if (transferCollections) - beatmapInfo.TransferCollectionReferences(r, oldMd5Hash); - - ProcessBeatmap?.Invoke((liveBeatmapSet, false)); - }); - } - - Debug.Assert(beatmapInfo.BeatmapSet != null); - - static string createBeatmapFilenameFromMetadata(BeatmapInfo beatmapInfo) - { - var metadata = beatmapInfo.Metadata; - return $"{metadata.Artist} - {metadata.Title} ({metadata.Author.Username}) [{beatmapInfo.DifficultyName}].osu".GetValidFilename(); - } + /// + /// Saves a new file against a given . + /// + /// The to save the content against. The file referenced by will be replaced. + /// The content to write. + /// The beatmap content to write, null if to be omitted. + public virtual void SaveNewBeatmap(BeatmapInfo beatmapInfo, IBeatmap beatmapContent, ISkin? beatmapSkin = null) + { + save(beatmapInfo, beatmapContent, beatmapSkin); } public void DeleteAllVideos() @@ -465,6 +414,69 @@ namespace osu.Game.Beatmaps setInfo.Status = BeatmapOnlineStatus.LocallyModified; } + private void save(BeatmapInfo beatmapInfo, IBeatmap beatmapContent, ISkin? beatmapSkin) + { + var setInfo = beatmapInfo.BeatmapSet; + Debug.Assert(setInfo != null); + + // Difficulty settings must be copied first due to the clone in `Beatmap<>.BeatmapInfo_Set`. + // This should hopefully be temporary, assuming said clone is eventually removed. + + // Warning: The directionality here is important. Changes have to be copied *from* beatmapContent (which comes from editor and is being saved) + // *to* the beatmapInfo (which is a database model and needs to receive values without the taiko slider velocity multiplier for correct operation). + // CopyTo() will undo such adjustments, while CopyFrom() will not. + beatmapContent.Difficulty.CopyTo(beatmapInfo.Difficulty); + + // All changes to metadata are made in the provided beatmapInfo, so this should be copied to the `IBeatmap` before encoding. + beatmapContent.BeatmapInfo = beatmapInfo; + + using (var stream = new MemoryStream()) + { + using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true)) + new LegacyBeatmapEncoder(beatmapContent, beatmapSkin).Encode(sw); + + stream.Seek(0, SeekOrigin.Begin); + + // AddFile generally handles updating/replacing files, but this is a case where the filename may have also changed so let's delete for simplicity. + var existingFileInfo = beatmapInfo.Path != null ? setInfo.GetFile(beatmapInfo.Path) : null; + string targetFilename = createBeatmapFilenameFromMetadata(beatmapInfo); + + // ensure that two difficulties from the set don't point at the same beatmap file. + if (setInfo.Beatmaps.Any(b => b.ID != beatmapInfo.ID && string.Equals(b.Path, targetFilename, StringComparison.OrdinalIgnoreCase))) + throw new InvalidOperationException($"{setInfo.GetDisplayString()} already has a difficulty with the name of '{beatmapInfo.DifficultyName}'."); + + if (existingFileInfo != null) + DeleteFile(setInfo, existingFileInfo); + + beatmapInfo.MD5Hash = stream.ComputeMD5Hash(); + beatmapInfo.Hash = stream.ComputeSHA2Hash(); + + beatmapInfo.LastLocalUpdate = DateTimeOffset.Now; + beatmapInfo.Status = BeatmapOnlineStatus.LocallyModified; + + AddFile(setInfo, stream, createBeatmapFilenameFromMetadata(beatmapInfo)); + + updateHashAndMarkDirty(setInfo); + + Realm.Write(r => + { + var liveBeatmapSet = r.Find(setInfo.ID); + + setInfo.CopyChangesToRealm(liveBeatmapSet); + + ProcessBeatmap?.Invoke((liveBeatmapSet, false)); + }); + } + + Debug.Assert(beatmapInfo.BeatmapSet != null); + + static string createBeatmapFilenameFromMetadata(BeatmapInfo beatmapInfo) + { + var metadata = beatmapInfo.Metadata; + return $"{metadata.Artist} - {metadata.Title} ({metadata.Author.Username}) [{beatmapInfo.DifficultyName}].osu".GetValidFilename(); + } + } + #region Implementation of ICanAcceptFiles public Task Import(params string[] paths) => beatmapImporter.Import(paths); diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 7161f34df2..915f3d4a2a 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -429,7 +429,10 @@ namespace osu.Game.Screens.Edit try { // save the loaded beatmap's data stream. - beatmapManager.Save(editorBeatmap.BeatmapInfo, editorBeatmap.PlayableBeatmap, editorBeatmap.BeatmapSkin, true); + if (isNewBeatmap) + beatmapManager.SaveNewBeatmap(editorBeatmap.BeatmapInfo, editorBeatmap.PlayableBeatmap, editorBeatmap.BeatmapSkin); + else + beatmapManager.SaveExistingBeatmap(editorBeatmap.BeatmapInfo, editorBeatmap.PlayableBeatmap, editorBeatmap.BeatmapSkin); } catch (Exception ex) { diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index e9d186fe35..8834911ff5 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -178,7 +178,12 @@ namespace osu.Game.Tests.Visual => testBeatmapManager.TestBeatmap; } - public override void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null, bool transferCollections = false) + public override void SaveExistingBeatmap(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) + { + // don't actually care about saving for this context. + } + + public override void SaveNewBeatmap(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) { // don't actually care about saving for this context. } From da03abc81235b04718fd64211b3b344ffe7dab77 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sat, 21 Jan 2023 17:08:42 -0800 Subject: [PATCH 098/430] Fix comment editor text boxes not having sound feedback --- osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs | 2 +- osu.Game/Graphics/UserInterface/OsuTextBox.cs | 7 +++++-- osu.Game/Overlays/Comments/CommentEditor.cs | 8 +------- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index 124d0c239a..dbf3b52572 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -262,7 +262,7 @@ namespace osu.Game.Tests.Visual.Online AddAssert("Nothing happened", () => this.ChildrenOfType().Any()); AddStep("Set report data", () => { - var field = this.ChildrenOfType().Single(); + var field = this.ChildrenOfType().Single().ChildrenOfType().Single(); field.Current.Value = report_text; var reason = this.ChildrenOfType>().Single(); reason.Current.Value = CommentReportReason.Other; diff --git a/osu.Game/Graphics/UserInterface/OsuTextBox.cs b/osu.Game/Graphics/UserInterface/OsuTextBox.cs index a65204e6b3..99803e2956 100644 --- a/osu.Game/Graphics/UserInterface/OsuTextBox.cs +++ b/osu.Game/Graphics/UserInterface/OsuTextBox.cs @@ -250,13 +250,16 @@ namespace osu.Game.Graphics.UserInterface protected override void OnFocus(FocusEvent e) { - BorderThickness = 3; + if (Masking) + BorderThickness = 3; + base.OnFocus(e); } protected override void OnFocusLost(FocusLostEvent e) { - BorderThickness = 0; + if (Masking) + BorderThickness = 0; base.OnFocusLost(e); } diff --git a/osu.Game/Overlays/Comments/CommentEditor.cs b/osu.Game/Overlays/Comments/CommentEditor.cs index ff417a2e15..2af7dd3093 100644 --- a/osu.Game/Overlays/Comments/CommentEditor.cs +++ b/osu.Game/Overlays/Comments/CommentEditor.cs @@ -147,7 +147,7 @@ namespace osu.Game.Overlays.Comments private void updateCommitButtonState() => commitButton.Enabled.Value = loadingSpinner.State.Value == Visibility.Hidden && !string.IsNullOrEmpty(Current.Value); - private partial class EditorTextBox : BasicTextBox + private partial class EditorTextBox : OsuTextBox { protected override float LeftRightPadding => side_padding; @@ -173,12 +173,6 @@ namespace osu.Game.Overlays.Comments { Font = OsuFont.GetFont(weight: FontWeight.Regular), }; - - protected override Drawable GetDrawableCharacter(char c) => new FallingDownContainer - { - AutoSizeAxes = Axes.Both, - Child = new OsuSpriteText { Text = c.ToString(), Font = OsuFont.GetFont(size: CalculatedTextSize) } - }; } protected partial class EditorButton : RoundedButton From a746cbc6ed471455583f1df5659014fd98214e4e Mon Sep 17 00:00:00 2001 From: Matheus Filipe dos Santos Reinert Date: Sun, 22 Jan 2023 01:14:33 -0300 Subject: [PATCH 099/430] Fix failSample still playing after player left FailOverlay --- osu.Game/Screens/Play/FailAnimation.cs | 8 +++++++- osu.Game/Screens/Play/Player.cs | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/FailAnimation.cs b/osu.Game/Screens/Play/FailAnimation.cs index 3f21f811c1..1eb1e69581 100644 --- a/osu.Game/Screens/Play/FailAnimation.cs +++ b/osu.Game/Screens/Play/FailAnimation.cs @@ -51,6 +51,7 @@ namespace osu.Game.Screens.Play private const float duration = 2500; private ISample? failSample; + private SampleChannel? failSampleChannel; [Resolved] private OsuConfigManager config { get; set; } = null!; @@ -125,7 +126,7 @@ namespace osu.Game.Screens.Play failHighPassFilter.CutoffTo(300); failLowPassFilter.CutoffTo(300, duration, Easing.OutCubic); - failSample?.Play(); + failSampleChannel = failSample?.Play(); track.AddAdjustment(AdjustableProperty.Frequency, trackFreq); track.AddAdjustment(AdjustableProperty.Volume, volumeAdjustment); @@ -153,6 +154,11 @@ namespace osu.Game.Screens.Play Background?.FadeColour(OsuColour.Gray(0.3f), 60); } + public void StopSample() + { + failSampleChannel?.Stop(); + } + public void RemoveFilters(bool resetTrackFrequency = true) { filtersRemoved = true; diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 77c16718f5..d7ac91fcea 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -612,6 +612,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(); + failAnimationLayer.StopSample(); + // 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). @@ -678,6 +680,7 @@ namespace osu.Game.Screens.Play sampleRestart?.Play(); RestartRequested?.Invoke(quickRestart); + failAnimationLayer.StopSample(); PerformExit(false); } From 05f77d2cabfa19201b98ee26f911261bf916642a Mon Sep 17 00:00:00 2001 From: EXtremeExploit Date: Sun, 22 Jan 2023 01:36:53 -0300 Subject: [PATCH 100/430] Add modes text to groups tooltip --- .../Visual/Online/TestSceneUserProfileOverlay.cs | 1 + .../Overlays/Profile/Header/Components/GroupBadge.cs | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs index f7e88e4437..fc8c2c0b6e 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs @@ -89,6 +89,7 @@ namespace osu.Game.Tests.Visual.Online Groups = new[] { 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" } } }, ProfileOrder = new[] diff --git a/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs b/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs index e62f1cebf0..654d2e9ef4 100644 --- a/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs @@ -20,7 +20,7 @@ namespace osu.Game.Overlays.Profile.Header.Components { public partial class GroupBadge : Container, IHasTooltip { - public LocalisableString TooltipText { get; } + public LocalisableString TooltipText { get; set; } public int TextSize { get; set; } = 12; @@ -34,7 +34,9 @@ namespace osu.Game.Overlays.Profile.Header.Components Masking = true; CornerRadius = 8; + TooltipText = group.Name; + } [BackgroundDependencyLoader] @@ -79,6 +81,14 @@ namespace osu.Game.Overlays.Profile.Header.Components })).ToList() ); } + + if (group.Playmodes?.Length > 0) + { + var badgeModesList = group.Playmodes.Select(p => rulesets.GetRuleset(p)?.Name).ToList(); + + string modesDisplay = string.Join(", ", badgeModesList); + this.TooltipText += $" ({modesDisplay})"; + } } } } From 8c208da3242d44c3407ff1d17e4830e3148152de Mon Sep 17 00:00:00 2001 From: EXtremeExploit Date: Sun, 22 Jan 2023 01:39:01 -0300 Subject: [PATCH 101/430] Cleanup --- osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs b/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs index 654d2e9ef4..9063bc82ec 100644 --- a/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs @@ -34,9 +34,7 @@ namespace osu.Game.Overlays.Profile.Header.Components Masking = true; CornerRadius = 8; - TooltipText = group.Name; - } [BackgroundDependencyLoader] From 2f3971b6fbf880aec0a95f18b31796c48f804a58 Mon Sep 17 00:00:00 2001 From: EXtremeExploit Date: Sun, 22 Jan 2023 01:40:00 -0300 Subject: [PATCH 102/430] Move code to already existing if block --- osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs b/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs index 9063bc82ec..b94774da26 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 icon.Size = new Vector2(TextSize - 1); })).ToList() ); - } - if (group.Playmodes?.Length > 0) - { var badgeModesList = group.Playmodes.Select(p => rulesets.GetRuleset(p)?.Name).ToList(); string modesDisplay = string.Join(", ", badgeModesList); From 2e1ba6ef49d9944bc79e6ed04ef602720556f4a6 Mon Sep 17 00:00:00 2001 From: Matheus Filipe dos Santos Reinert Date: Sun, 22 Jan 2023 01:43:40 -0300 Subject: [PATCH 103/430] Create StopSampleAndRemoveFilters method and change RemoveFilters to private --- osu.Game/Screens/Play/FailAnimation.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/FailAnimation.cs b/osu.Game/Screens/Play/FailAnimation.cs index 1eb1e69581..b35bd9db8c 100644 --- a/osu.Game/Screens/Play/FailAnimation.cs +++ b/osu.Game/Screens/Play/FailAnimation.cs @@ -120,7 +120,7 @@ namespace osu.Game.Screens.Play this.TransformBindableTo(trackFreq, 0, duration).OnComplete(_ => { // Don't reset frequency as the pause screen may appear post transform, causing a second frequency sweep. - RemoveFilters(false); + removeFilters(false); OnComplete?.Invoke(); }); @@ -159,7 +159,13 @@ namespace osu.Game.Screens.Play failSampleChannel?.Stop(); } - public void RemoveFilters(bool resetTrackFrequency = true) + public void StopSampleAndRemoveFilters() + { + StopSample(); + removeFilters(); + } + + private void removeFilters(bool resetTrackFrequency = true) { filtersRemoved = true; From 5b1a23c697b2eb80732ee416c32febccae6a1540 Mon Sep 17 00:00:00 2001 From: Matheus Filipe dos Santos Reinert Date: Sun, 22 Jan 2023 01:44:16 -0300 Subject: [PATCH 104/430] Replace RemoveFilters call with StopSampleAndRemoveFilters --- osu.Game/Screens/Play/Player.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index d7ac91fcea..654dc2ccb6 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -612,8 +612,6 @@ namespace osu.Game.Screens.Play // if an exit has been requested, cancel any pending completion (the user has shown intention to exit). resultsDisplayDelegate?.Cancel(); - failAnimationLayer.StopSample(); - // 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). @@ -1075,7 +1073,7 @@ namespace osu.Game.Screens.Play public override bool OnExiting(ScreenExitEvent e) { screenSuspension?.RemoveAndDisposeImmediately(); - failAnimationLayer?.RemoveFilters(); + failAnimationLayer?.StopSampleAndRemoveFilters(); if (LoadedBeatmapSuccessfully) { From 704074324959abb62edd912c43dbec43708f410f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 22 Jan 2023 13:47:31 +0900 Subject: [PATCH 105/430] Add search keywords for screen scaling sub-settings --- .../Overlays/Settings/Sections/Graphics/LayoutSettings.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index bad06732d0..f140c14a0b 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -133,6 +133,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics new SettingsSlider { LabelText = GraphicsSettingsStrings.HorizontalPosition, + Keywords = new[] { "screen", "scaling" }, Current = scalingPositionX, KeyboardStep = 0.01f, DisplayAsPercentage = true @@ -140,6 +141,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics new SettingsSlider { LabelText = GraphicsSettingsStrings.VerticalPosition, + Keywords = new[] { "screen", "scaling" }, Current = scalingPositionY, KeyboardStep = 0.01f, DisplayAsPercentage = true @@ -147,6 +149,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics new SettingsSlider { LabelText = GraphicsSettingsStrings.HorizontalScale, + Keywords = new[] { "screen", "scaling" }, Current = scalingSizeX, KeyboardStep = 0.01f, DisplayAsPercentage = true @@ -154,6 +157,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics new SettingsSlider { LabelText = GraphicsSettingsStrings.VerticalScale, + Keywords = new[] { "screen", "scaling" }, Current = scalingSizeY, KeyboardStep = 0.01f, DisplayAsPercentage = true From 0edfd24410ed72a826dada58021bc414fdefe543 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 22 Jan 2023 09:24:12 +0100 Subject: [PATCH 106/430] Remove unnecessary sample stop in `Restart()` It is unnecessary, as a successful restart will exit the current player screen, and `OnExiting()` has another `StopSampleAndRemoveFilters()` call, which means that in the restart flow the sample was actually getting stopped twice. Standard exit flow is fine, it only stopped the sample once. --- osu.Game/Screens/Play/Player.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 654dc2ccb6..a0b9e9352a 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -678,7 +678,6 @@ namespace osu.Game.Screens.Play sampleRestart?.Play(); RestartRequested?.Invoke(quickRestart); - failAnimationLayer.StopSample(); PerformExit(false); } From 9e4e85e3e3512022697b6b64402b371faafaa14b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 22 Jan 2023 09:26:01 +0100 Subject: [PATCH 107/430] Inline `StopSample()` into `StopSampleAndRemoveFilters()` The first method no longer has any callers except for the second one. --- osu.Game/Screens/Play/FailAnimation.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/osu.Game/Screens/Play/FailAnimation.cs b/osu.Game/Screens/Play/FailAnimation.cs index b35bd9db8c..e01d668f5d 100644 --- a/osu.Game/Screens/Play/FailAnimation.cs +++ b/osu.Game/Screens/Play/FailAnimation.cs @@ -154,14 +154,9 @@ namespace osu.Game.Screens.Play Background?.FadeColour(OsuColour.Gray(0.3f), 60); } - public void StopSample() - { - failSampleChannel?.Stop(); - } - public void StopSampleAndRemoveFilters() { - StopSample(); + failSampleChannel?.Stop(); removeFilters(); } From 06aa3f779811c3b4506faa909717b6ff1cd03f30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 22 Jan 2023 09:27:06 +0100 Subject: [PATCH 108/430] Rename `Stop{SampleAndRemoveFilters -> }()` Now that just one method for stopping samples is left, let's just repurpose st as the general "stop global effects" method rather than have it there with a hyperspecific name. It also has good symmetry, as there already was a `Start()` method in the class. --- osu.Game/Screens/Play/FailAnimation.cs | 5 ++++- osu.Game/Screens/Play/Player.cs | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/FailAnimation.cs b/osu.Game/Screens/Play/FailAnimation.cs index e01d668f5d..0214d33549 100644 --- a/osu.Game/Screens/Play/FailAnimation.cs +++ b/osu.Game/Screens/Play/FailAnimation.cs @@ -154,7 +154,10 @@ namespace osu.Game.Screens.Play Background?.FadeColour(OsuColour.Gray(0.3f), 60); } - public void StopSampleAndRemoveFilters() + /// + /// Stops any and all persistent effects added by the ongoing fail animation. + /// + public void Stop() { failSampleChannel?.Stop(); removeFilters(); diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index a0b9e9352a..0d208e6d9b 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -1072,7 +1072,7 @@ namespace osu.Game.Screens.Play public override bool OnExiting(ScreenExitEvent e) { screenSuspension?.RemoveAndDisposeImmediately(); - failAnimationLayer?.StopSampleAndRemoveFilters(); + failAnimationLayer?.Stop(); if (LoadedBeatmapSuccessfully) { From b98da506c1a15c87be7961b7879e719f6b87a24f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 22 Jan 2023 10:07:47 +0100 Subject: [PATCH 109/430] Fix code quality inspection --- 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 b94774da26..3aa5828439 100644 --- a/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs @@ -82,7 +82,7 @@ namespace osu.Game.Overlays.Profile.Header.Components var badgeModesList = group.Playmodes.Select(p => rulesets.GetRuleset(p)?.Name).ToList(); string modesDisplay = string.Join(", ", badgeModesList); - this.TooltipText += $" ({modesDisplay})"; + TooltipText += $" ({modesDisplay})"; } } } From 9bde1ef9bfde013184de39cfe06243b2e2ad0f5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 22 Jan 2023 10:09:08 +0100 Subject: [PATCH 110/430] Privatise setter --- 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 3aa5828439..4d6ee36254 100644 --- a/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/GroupBadge.cs @@ -20,7 +20,7 @@ namespace osu.Game.Overlays.Profile.Header.Components { public partial class GroupBadge : Container, IHasTooltip { - public LocalisableString TooltipText { get; set; } + public LocalisableString TooltipText { get; private set; } public int TextSize { get; set; } = 12; From 64c96549101a7006ea946f80d23a2aebb019a16c Mon Sep 17 00:00:00 2001 From: EXtremeExploit Date: Sun, 22 Jan 2023 13:32:05 -0300 Subject: [PATCH 111/430] 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 112/430] 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 113/430] 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 114/430] 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 115/430] 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 116/430] 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 117/430] 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 118/430] 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 119/430] 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 120/430] 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 121/430] 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 73f083a3166e543cbada59d2cae13bfaa71c5596 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Jan 2023 14:13:46 +0900 Subject: [PATCH 122/430] Refactor how additional points are provided to avoid confusion --- .../Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs | 8 +++----- osu.Game/Rulesets/Edit/SelectionBlueprint.cs | 9 +++++++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 660976ba33..b502839e22 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -409,11 +409,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders public override Vector2 ScreenSpaceSelectionPoint => DrawableObject.SliderBody?.ToScreenSpace(DrawableObject.SliderBody.PathOffset) ?? BodyPiece.ToScreenSpace(BodyPiece.PathStartLocation); - public override Vector2[] ScreenSpaceSnapPoints => new Vector2[] - { - ScreenSpaceSelectionPoint, - DrawableObject.SliderBody?.ToScreenSpace(DrawableObject.SliderBody.PathEndOffset) - ?? BodyPiece.ToScreenSpace(BodyPiece.PathEndLocation) + protected override Vector2[] ScreenSpaceAdditionalNodes => new[] + { + DrawableObject.SliderBody?.ToScreenSpace(DrawableObject.SliderBody.PathEndOffset) ?? BodyPiece.ToScreenSpace(BodyPiece.PathEndLocation) }; public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => diff --git a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs index b2f2fa8a9b..d36ed02210 100644 --- a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs +++ b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs @@ -4,7 +4,7 @@ #nullable disable using System; -using System.Collections.Generic; +using System.Linq; using osu.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -130,11 +130,16 @@ namespace osu.Game.Rulesets.Edit /// public virtual Vector2 ScreenSpaceSelectionPoint => ScreenSpaceDrawQuad.Centre; + /// + /// Any points that should be used for snapping purposes in addition to . Exposed via . + /// + protected virtual Vector2[] ScreenSpaceAdditionalNodes => Array.Empty(); + /// /// The screen-space collection of base points that cause this to be selected via a drag. /// The first element of this collection is /// - public virtual Vector2[] ScreenSpaceSnapPoints => new Vector2[] { ScreenSpaceSelectionPoint }; + public Vector2[] ScreenSpaceSnapPoints => ScreenSpaceAdditionalNodes.Prepend(ScreenSpaceSelectionPoint).ToArray(); /// /// The screen-space quad that outlines this for selections. From 2ed9fe3747cc743bbf6ec1410c21ab68349edc08 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Jan 2023 15:10:26 +0900 Subject: [PATCH 123/430] Add support for externally specified keywords in `SettingsButton`s --- osu.Game/Overlays/Settings/SettingsButton.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Settings/SettingsButton.cs b/osu.Game/Overlays/Settings/SettingsButton.cs index 5091ddc2d0..a837444758 100644 --- a/osu.Game/Overlays/Settings/SettingsButton.cs +++ b/osu.Game/Overlays/Settings/SettingsButton.cs @@ -1,8 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Collections.Generic; -using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -22,6 +22,8 @@ namespace osu.Game.Overlays.Settings public LocalisableString TooltipText { get; set; } + public IEnumerable Keywords { get; set; } = Array.Empty(); + public BindableBool CanBeShown { get; } = new BindableBool(true); IBindable IConditionalFilterable.CanBeShown => CanBeShown; @@ -30,9 +32,13 @@ namespace osu.Game.Overlays.Settings get { if (TooltipText != default) - return base.FilterTerms.Append(TooltipText); + yield return TooltipText; - return base.FilterTerms; + foreach (string s in Keywords) + yield return s; + + foreach (LocalisableString s in base.FilterTerms) + yield return s; } } } From 7ebd31d42f2ec46a210dd0a2bff7955c6ee191a2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Jan 2023 15:10:34 +0900 Subject: [PATCH 124/430] Add more keywords to settings based on feedback --- osu.Game/Overlays/Settings/Sections/Gameplay/InputSettings.cs | 1 + osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs | 1 + osu.Game/Overlays/Settings/Sections/GeneralSection.cs | 1 + osu.Game/Overlays/Settings/Sections/Input/BindingSettings.cs | 2 +- 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/InputSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/InputSettings.cs index 4d027cf8cb..9291dfe923 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/InputSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/InputSettings.cs @@ -35,6 +35,7 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay new SettingsCheckbox { LabelText = SkinSettingsStrings.GameplayCursorDuringTouch, + Keywords = new[] { @"touchscreen" }, Current = config.GetBindable(OsuSetting.GameplayCursorDuringTouch) }, }; diff --git a/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs b/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs index 55be06c765..2f68b3a82f 100644 --- a/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs @@ -70,6 +70,7 @@ namespace osu.Game.Overlays.Settings.Sections.General Add(new SettingsButton { Text = GeneralSettingsStrings.OpenOsuFolder, + Keywords = new[] { @"logs", @"files", @"access", "directory" }, Action = () => storage.PresentExternally(), }); diff --git a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs index d4fd78f0c8..c5274d6223 100644 --- a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs +++ b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs @@ -34,6 +34,7 @@ namespace osu.Game.Overlays.Settings.Sections new SettingsButton { Text = GeneralSettingsStrings.RunSetupWizard, + Keywords = new[] { @"first run", @"initial", @"getting started" }, TooltipText = FirstRunSetupOverlayStrings.FirstRunSetupDescription, Action = () => firstRunSetupOverlay?.Show(), }, diff --git a/osu.Game/Overlays/Settings/Sections/Input/BindingSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/BindingSettings.cs index dbd7949206..2b478f6af3 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/BindingSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/BindingSettings.cs @@ -15,7 +15,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input { protected override LocalisableString Header => BindingSettingsStrings.ShortcutAndGameplayBindings; - public override IEnumerable FilterTerms => base.FilterTerms.Concat(new LocalisableString[] { "keybindings" }); + public override IEnumerable FilterTerms => base.FilterTerms.Concat(new LocalisableString[] { @"keybindings", @"controls", @"keyboard", @"keys" }); public BindingSettings(KeyBindingPanel keyConfig) { From 5afb733fb2e8dbf4350880699350be590bd726f6 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Mon, 23 Jan 2023 15:26:28 +0900 Subject: [PATCH 125/430] change IssueTemplatePreviewTimeConflict's text --- osu.Game.Tests/Editing/Checks/CheckPreviewTimeTest.cs | 2 +- osu.Game/Rulesets/Edit/Checks/CheckPreviewTime.cs | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Editing/Checks/CheckPreviewTimeTest.cs b/osu.Game.Tests/Editing/Checks/CheckPreviewTimeTest.cs index 59ff8d4923..2b7d37dc81 100644 --- a/osu.Game.Tests/Editing/Checks/CheckPreviewTimeTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckPreviewTimeTest.cs @@ -67,7 +67,7 @@ namespace osu.Game.Tests.Editing.Checks Assert.That(issues, Has.Count.EqualTo(1)); Assert.That(issues.Single().Template is CheckPreviewTime.IssueTemplatePreviewTimeConflict); - Assert.That(issues.Single().Arguments.Single().ToString() == "Test1"); + Assert.That(issues.Single().Arguments.FirstOrDefault()?.ToString() == "Test1"); } private void setNoPreviewTimeBeatmap() diff --git a/osu.Game/Rulesets/Edit/Checks/CheckPreviewTime.cs b/osu.Game/Rulesets/Edit/Checks/CheckPreviewTime.cs index 4fad8c0af6..05e49eba84 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckPreviewTime.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckPreviewTime.cs @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Edit.Checks if (diff.Metadata.PreviewTime != previewTime) { - yield return new IssueTemplatePreviewTimeConflict(this).Create(diff.DifficultyName); + yield return new IssueTemplatePreviewTimeConflict(this).Create(diff.DifficultyName, previewTime, diff.Metadata.PreviewTime); } } } @@ -44,11 +44,15 @@ namespace osu.Game.Rulesets.Edit.Checks public class IssueTemplatePreviewTimeConflict : IssueTemplate { public IssueTemplatePreviewTimeConflict(ICheck check) - : base(check, IssueType.Warning, "Audio preview time conflicts with {0} diff") + : base(check, IssueType.Warning, "Audio preview time {1} doesn't match \"{0}\"'s preview time {2}") { } - public Issue Create(string diffName) => new Issue(this, diffName); + public Issue Create(string diffName, int originalTime, int conflictTime) => + // preview time should show (not set) when it is not set. + new Issue(this, diffName, + originalTime != -1 ? $"({originalTime:N0})" : "(not set)", + conflictTime != -1 ? $"({conflictTime:N0})" : "(not set)"); } public class IssueTemplateHasNoPreviewTime : IssueTemplate From 9c2494383fda4c2a6b92205946e495355c444a8e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Jan 2023 15:43:52 +0900 Subject: [PATCH 126/430] Rename fetch method to be non-plural to match all others --- osu.Game/Graphics/OsuColour.cs | 2 +- osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/OsuColour.cs b/osu.Game/Graphics/OsuColour.cs index 5e2649377a..e06f6b3fd0 100644 --- a/osu.Game/Graphics/OsuColour.cs +++ b/osu.Game/Graphics/OsuColour.cs @@ -192,7 +192,7 @@ namespace osu.Game.Graphics /// Retrieves colour for a . /// See https://www.figma.com/file/YHWhp9wZ089YXgB7pe6L1k/Tier-Colours /// - public ColourInfo ForRankingTiers(RankingTier tier) + public ColourInfo ForRankingTier(RankingTier tier) { switch (tier) { diff --git a/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs b/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs index ddc084a600..9b4df7672d 100644 --- a/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs @@ -91,7 +91,7 @@ namespace osu.Game.Overlays.Profile.Header.Components tier = RankingTier.Lustrous; } - return osuColour.ForRankingTiers(tier); + return osuColour.ForRankingTier(tier); } } } From 736965e0099232f64d34bdc50eaa96de3a078701 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Jan 2023 15:45:44 +0900 Subject: [PATCH 127/430] Fix test scene potentially overflowing visible region --- osu.Game.Tests/Visual/Online/TestSceneLevelBadge.cs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneLevelBadge.cs b/osu.Game.Tests/Visual/Online/TestSceneLevelBadge.cs index fef6dd0477..1fd54ca50f 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneLevelBadge.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneLevelBadge.cs @@ -37,16 +37,15 @@ namespace osu.Game.Tests.Visual.Online { new FillFlowContainer { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Horizontal, + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Full, Spacing = new Vector2(5), - ChildrenEnumerable = levels.Select(l => new LevelBadge + ChildrenEnumerable = levels.Select(level => new LevelBadge { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, Size = new Vector2(60), - LevelInfo = { Value = l } + LevelInfo = { Value = level } }) } }; From 338a14ff69c9dcda990b2c714c2831028f8ed1cf Mon Sep 17 00:00:00 2001 From: itsMapleLeaf <19603573+itsMapleLeaf@users.noreply.github.com> Date: Mon, 23 Jan 2023 01:01:45 -0600 Subject: [PATCH 128/430] new mania hold tail --- .../Skinning/Argon/ArgonHoldNoteTailPiece.cs | 76 +++++++++++-------- .../Skinning/Argon/ArgonNotePiece.cs | 4 +- 2 files changed, 45 insertions(+), 35 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs index a2166a6708..6f6270c1f5 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs @@ -3,13 +3,13 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI.Scrolling; +using osuTK; using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.Skinning.Argon @@ -19,45 +19,57 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon private readonly IBindable direction = new Bindable(); private readonly IBindable accentColour = new Bindable(); - private readonly Box colouredBox; - private readonly Box shadow; + private readonly Container spriteContainer; + private readonly Container shadeContainer; + private readonly Circle hitLine; public ArgonHoldNoteTailPiece() { RelativeSizeAxes = Axes.X; - Height = ArgonNotePiece.NOTE_HEIGHT; + + // multiply by two so that the hold body extends up to the height of the note head accent + Height = ArgonNotePiece.NOTE_HEIGHT * ArgonNotePiece.NOTE_ACCENT_RATIO * 2; CornerRadius = ArgonNotePiece.CORNER_RADIUS; Masking = true; InternalChildren = new Drawable[] { - shadow = new Box - { + shadeContainer = new Container { RelativeSizeAxes = Axes.Both, - }, - new Container - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.Both, - Height = 0.82f, - Masking = true, + Height = 0.5f, CornerRadius = ArgonNotePiece.CORNER_RADIUS, - Children = new Drawable[] - { - colouredBox = new Box + Masking = true, + Children = new Drawable[] { + new Box { RelativeSizeAxes = Axes.Both, - } - } + Colour = Color4.Black, + Alpha = 0.2f, + }, + }, }, - new Circle - { + spriteContainer = new Container { + RelativeSizeAxes = Axes.X, + Height = ArgonNotePiece.NOTE_HEIGHT, + Children = new Drawable[] + { + new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Y = 4, + Icon = FontAwesome.Solid.AngleDown, + Size = new Vector2(20), + Scale = new Vector2(1, 0.7f), + Colour = Color4.White, + Alpha = 0.2f, + }, + }, + }, + hitLine = new Circle { RelativeSizeAxes = Axes.X, Height = ArgonNotePiece.CORNER_RADIUS * 2, - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, }, }; } @@ -77,19 +89,17 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon private void onDirectionChanged(ValueChangedEvent direction) { - colouredBox.Anchor = colouredBox.Origin = direction.NewValue == ScrollingDirection.Up - ? Anchor.TopCentre - : Anchor.BottomCentre; + hitLine.Anchor = hitLine.Origin = + spriteContainer.Anchor = spriteContainer.Origin = + shadeContainer.Anchor = shadeContainer.Origin = + direction.NewValue == ScrollingDirection.Up + ? Anchor.TopCentre + : Anchor.BottomCentre; } private void onAccentChanged(ValueChangedEvent accent) { - colouredBox.Colour = ColourInfo.GradientVertical( - accent.NewValue, - accent.NewValue.Darken(0.1f) - ); - - shadow.Colour = accent.NewValue.Darken(0.5f); + hitLine.Colour = accent.NewValue; } } } diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonNotePiece.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonNotePiece.cs index 25b1965c18..f680483634 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonNotePiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonNotePiece.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon internal partial class ArgonNotePiece : CompositeDrawable { public const float NOTE_HEIGHT = 42; - + public const float NOTE_ACCENT_RATIO = 0.82f; public const float CORNER_RADIUS = 3.4f; private readonly IBindable direction = new Bindable(); @@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, RelativeSizeAxes = Axes.Both, - Height = 0.82f, + Height = NOTE_ACCENT_RATIO, Masking = true, CornerRadius = CORNER_RADIUS, Children = new Drawable[] From 9a053f114ebc0040d850f94e5b62f41f0f15c587 Mon Sep 17 00:00:00 2001 From: itsMapleLeaf <19603573+itsMapleLeaf@users.noreply.github.com> Date: Mon, 23 Jan 2023 01:50:50 -0600 Subject: [PATCH 129/430] remove sprite --- .../Skinning/Argon/ArgonHoldNoteTailPiece.cs | 26 ++----------------- 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs index 6f6270c1f5..02325904c4 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs @@ -6,10 +6,8 @@ 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.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI.Scrolling; -using osuTK; using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.Skinning.Argon @@ -19,7 +17,6 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon private readonly IBindable direction = new Bindable(); private readonly IBindable accentColour = new Bindable(); - private readonly Container spriteContainer; private readonly Container shadeContainer; private readonly Circle hitLine; @@ -28,7 +25,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon RelativeSizeAxes = Axes.X; // multiply by two so that the hold body extends up to the height of the note head accent - Height = ArgonNotePiece.NOTE_HEIGHT * ArgonNotePiece.NOTE_ACCENT_RATIO * 2; + Height = ArgonNotePiece.NOTE_HEIGHT * 2; CornerRadius = ArgonNotePiece.CORNER_RADIUS; Masking = true; @@ -45,25 +42,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon { RelativeSizeAxes = Axes.Both, Colour = Color4.Black, - Alpha = 0.2f, - }, - }, - }, - spriteContainer = new Container { - RelativeSizeAxes = Axes.X, - Height = ArgonNotePiece.NOTE_HEIGHT, - Children = new Drawable[] - { - new SpriteIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Y = 4, - Icon = FontAwesome.Solid.AngleDown, - Size = new Vector2(20), - Scale = new Vector2(1, 0.7f), - Colour = Color4.White, - Alpha = 0.2f, + Alpha = 0.4f, }, }, }, @@ -90,7 +69,6 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon private void onDirectionChanged(ValueChangedEvent direction) { hitLine.Anchor = hitLine.Origin = - spriteContainer.Anchor = spriteContainer.Origin = shadeContainer.Anchor = shadeContainer.Origin = direction.NewValue == ScrollingDirection.Up ? Anchor.TopCentre From c4d5957ac3238009529833229ee63ac16377b1a2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Jan 2023 17:07:27 +0900 Subject: [PATCH 130/430] Add empty space tap-streaming support for osu! ruleset on touchscreen devices --- .../TestSceneTouchInput.cs | 147 +++++++++++++++++- osu.Game.Rulesets.Osu/OsuInputManager.cs | 5 + .../UI/OsuTouchInputMapper.cs | 40 ++++- 3 files changed, 186 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs index 10d0143351..5530bd4b99 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs @@ -13,7 +13,12 @@ using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Input.States; using osu.Framework.Testing; +using osu.Framework.Timing; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Configuration; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Screens.Play; using osu.Game.Tests.Visual; using osuTK; @@ -33,6 +38,8 @@ namespace osu.Game.Rulesets.Osu.Tests private OsuInputManager osuInputManager = null!; + private Container mainContent = null!; + [SetUpSteps] public void SetUpSteps() { @@ -44,7 +51,7 @@ namespace osu.Game.Rulesets.Osu.Tests { osuInputManager = new OsuInputManager(new OsuRuleset().RulesetInfo) { - Child = new Container + Child = mainContent = new Container { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -54,12 +61,14 @@ namespace osu.Game.Rulesets.Osu.Tests { Anchor = Anchor.Centre, Origin = Anchor.CentreRight, + Depth = float.MinValue, X = -100, }, rightKeyCounter = new TestActionKeyCounter(OsuAction.RightButton) { Anchor = Anchor.Centre, Origin = Anchor.CentreLeft, + Depth = float.MinValue, X = 100, } }, @@ -116,9 +125,127 @@ namespace osu.Game.Rulesets.Osu.Tests endTouch(TouchSource.Touch2); checkPosition(TouchSource.Touch2); - // note that touch1 was never ended, but becomes active for tracking again. + // note that touch1 was never ended, but is no longer valid for touch input due to touch 2 occurring. beginTouch(TouchSource.Touch1); + checkPosition(TouchSource.Touch2); + } + + [Test] + public void TestStreamInput() + { + // In this scenario, the user is tapping on the first object in a stream, + // then using one or two fingers in empty space to continue the stream. + + addHitCircleAt(TouchSource.Touch1); + beginTouch(TouchSource.Touch1); + + // The first touch is handled as normal. + assertKeyCounter(1, 0); + checkPressed(OsuAction.LeftButton); checkPosition(TouchSource.Touch1); + + // The second touch should release the first, and also act as a right button. + beginTouch(TouchSource.Touch2); + + assertKeyCounter(1, 1); + // Importantly, this is different from the simple case because an object was interacted with + // in the first touch, but not the second touch. + checkNotPressed(OsuAction.LeftButton); + checkPressed(OsuAction.RightButton); + // Also importantly, the positional part of the second touch is ignored. + checkPosition(TouchSource.Touch1); + + // In this scenario, a third touch should be allowed, and handled similarly to the second. + beginTouch(TouchSource.Touch3); + + assertKeyCounter(2, 1); + checkPressed(OsuAction.LeftButton); + checkPressed(OsuAction.RightButton); + // Position is still ignored. + checkPosition(TouchSource.Touch1); + + endTouch(TouchSource.Touch2); + + checkPressed(OsuAction.LeftButton); + checkNotPressed(OsuAction.RightButton); + // Position is still ignored. + checkPosition(TouchSource.Touch1); + + // User continues streaming + beginTouch(TouchSource.Touch2); + + assertKeyCounter(2, 2); + checkPressed(OsuAction.LeftButton); + checkPressed(OsuAction.RightButton); + // Position is still ignored. + checkPosition(TouchSource.Touch1); + + // In this mode a maximum of three touches should be supported. + // A fourth touch should result in no changes anywhere. + beginTouch(TouchSource.Touch4); + assertKeyCounter(2, 2); + checkPressed(OsuAction.LeftButton); + checkPressed(OsuAction.RightButton); + checkPosition(TouchSource.Touch1); + endTouch(TouchSource.Touch4); + } + + [Test] + public void TestNonStreamOverlappingDirectTouchesWithRelease() + { + // In this scenario, the user is tapping on three circles directly while correctly releasing the first touch. + // All three should be recognised. + + addHitCircleAt(TouchSource.Touch1); + addHitCircleAt(TouchSource.Touch2); + addHitCircleAt(TouchSource.Touch3); + + beginTouch(TouchSource.Touch1); + assertKeyCounter(1, 0); + checkPressed(OsuAction.LeftButton); + checkPosition(TouchSource.Touch1); + + beginTouch(TouchSource.Touch2); + assertKeyCounter(1, 1); + checkPressed(OsuAction.LeftButton); + checkPressed(OsuAction.RightButton); + checkPosition(TouchSource.Touch2); + + endTouch(TouchSource.Touch1); + + beginTouch(TouchSource.Touch3); + assertKeyCounter(2, 1); + checkPressed(OsuAction.LeftButton); + checkPressed(OsuAction.RightButton); + checkPosition(TouchSource.Touch3); + } + + [Test] + public void TestNonStreamOverlappingDirectTouchesWithoutRelease() + { + // In this scenario, the user is tapping on three circles directly without releasing any touches. + // The first two should be recognised, but a third should not (as the user already has two fingers down). + + addHitCircleAt(TouchSource.Touch1); + addHitCircleAt(TouchSource.Touch2); + addHitCircleAt(TouchSource.Touch3); + + beginTouch(TouchSource.Touch1); + assertKeyCounter(1, 0); + checkPressed(OsuAction.LeftButton); + checkPosition(TouchSource.Touch1); + + beginTouch(TouchSource.Touch2); + assertKeyCounter(1, 1); + checkPressed(OsuAction.LeftButton); + checkPressed(OsuAction.RightButton); + checkPosition(TouchSource.Touch2); + + beginTouch(TouchSource.Touch3); + assertKeyCounter(1, 1); + checkPressed(OsuAction.LeftButton); + checkPressed(OsuAction.RightButton); + checkPosition(TouchSource.Touch3); } [Test] @@ -263,6 +390,22 @@ namespace osu.Game.Rulesets.Osu.Tests assertKeyCounter(1, 1); } + private void addHitCircleAt(TouchSource source) + { + AddStep($"Add circle at {source}", () => + { + var hitCircle = new HitCircle(); + + hitCircle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + + mainContent.Add(new DrawableHitCircle(hitCircle) + { + Clock = new FramedClock(new ManualClock()), + Position = mainContent.ToLocalSpace(getSanePositionForSource(source)), + }); + }); + } + private void beginTouch(TouchSource source, Vector2? screenSpacePosition = null) => AddStep($"Begin touch for {source}", () => InputManager.BeginTouch(new Touch(source, screenSpacePosition ??= getSanePositionForSource(source)))); diff --git a/osu.Game.Rulesets.Osu/OsuInputManager.cs b/osu.Game.Rulesets.Osu/OsuInputManager.cs index 99ae706369..465dd13362 100644 --- a/osu.Game.Rulesets.Osu/OsuInputManager.cs +++ b/osu.Game.Rulesets.Osu/OsuInputManager.cs @@ -9,8 +9,10 @@ using osu.Framework.Graphics; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Input.Bindings; +using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.UI; +using osuTK; namespace osu.Game.Rulesets.Osu { @@ -40,6 +42,9 @@ namespace osu.Game.Rulesets.Osu protected override KeyBindingContainer CreateKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) => new OsuKeyBindingContainer(ruleset, variant, unique); + public bool CheckScreenSpaceActionPressJudgeable(Vector2 screenSpacePosition) => + NonPositionalInputQueue.OfType().Any(c => c.ReceivePositionalInputAt(screenSpacePosition)); + public OsuInputManager(RulesetInfo ruleset) : base(ruleset, 0, SimultaneousBindingMode.Unique) { diff --git a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs index c75e179443..9842e24d05 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs @@ -44,6 +44,8 @@ namespace osu.Game.Rulesets.Osu.UI handleTouchMovement(e); } + private TrackedTouch? positionTrackingTouch; + protected override bool OnTouchDown(TouchDownEvent e) { OsuAction action = trackedTouches.Any(t => t.Action == OsuAction.LeftButton) @@ -53,7 +55,31 @@ namespace osu.Game.Rulesets.Osu.UI // Ignore any taps which trigger an action which is already handled. But track them for potential positional input in the future. bool shouldResultInAction = osuInputManager.AllowGameplayInputs && !mouseDisabled.Value && trackedTouches.All(t => t.Action != action); - trackedTouches.Add(new TrackedTouch(e.Touch.Source, shouldResultInAction ? action : null)); + // If we can actually accept as an action, check whether this tap was on a circle's receptor. + // This case gets special handling to allow for empty-space stream tapping. + bool isDirectCircleTouch = osuInputManager.CheckScreenSpaceActionPressJudgeable(e.ScreenSpaceTouchDownPosition); + + var trackedTouch = new TrackedTouch(e.Touch.Source, shouldResultInAction ? action : null, isDirectCircleTouch); + + if (isDirectCircleTouch) + positionTrackingTouch = trackedTouch; + else + { + // If no direct touch is registered, we always use the new (latest) touch for positional tracking. + if (positionTrackingTouch?.DirectTouch != true) + positionTrackingTouch = trackedTouch; + else + { + // If not a direct circle touch, consider whether to release the an original direct touch. + if (positionTrackingTouch.DirectTouch && positionTrackingTouch.Action is OsuAction directTouchAction) + { + osuInputManager.KeyBindingContainer.TriggerReleased(directTouchAction); + positionTrackingTouch.Action = null; + } + } + } + + trackedTouches.Add(trackedTouch); // Important to update position before triggering the pressed action. handleTouchMovement(e); @@ -67,7 +93,7 @@ namespace osu.Game.Rulesets.Osu.UI private void handleTouchMovement(TouchEvent touchEvent) { // Movement should only be tracked for the most recent touch. - if (touchEvent.Touch.Source != trackedTouches.Last().Source) + if (touchEvent.Touch.Source != positionTrackingTouch?.Source) return; if (!osuInputManager.AllowUserCursorMovement) @@ -83,6 +109,9 @@ namespace osu.Game.Rulesets.Osu.UI if (tracked.Action is OsuAction action) osuInputManager.KeyBindingContainer.TriggerReleased(action); + if (positionTrackingTouch == tracked) + positionTrackingTouch = null; + trackedTouches.Remove(tracked); base.OnTouchUp(e); @@ -92,12 +121,15 @@ namespace osu.Game.Rulesets.Osu.UI { public readonly TouchSource Source; - public readonly OsuAction? Action; + public OsuAction? Action; - public TrackedTouch(TouchSource source, OsuAction? action) + public readonly bool DirectTouch; + + public TrackedTouch(TouchSource source, OsuAction? action, bool directTouch) { Source = source; Action = action; + DirectTouch = directTouch; } } } From 238a3833e23ba829d913e73872ac6aa1b1883e80 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Jan 2023 17:28:01 +0900 Subject: [PATCH 131/430] Add test coverage of stream scenario with an initial finger down --- .../TestSceneTouchInput.cs | 50 ++++++++++++++++++- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs index 5530bd4b99..4d119bc2ea 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs @@ -148,8 +148,8 @@ namespace osu.Game.Rulesets.Osu.Tests beginTouch(TouchSource.Touch2); assertKeyCounter(1, 1); - // Importantly, this is different from the simple case because an object was interacted with - // in the first touch, but not the second touch. + // Importantly, this is different from the simple case because an object was interacted with in the first touch, but not the second touch. + // left button is automatically released. checkNotPressed(OsuAction.LeftButton); checkPressed(OsuAction.RightButton); // Also importantly, the positional part of the second touch is ignored. @@ -190,6 +190,52 @@ namespace osu.Game.Rulesets.Osu.Tests endTouch(TouchSource.Touch4); } + [Test] + public void TestStreamInputWithInitialTouchDown() + { + // In this scenario, the user is wanting to use stream input but we start with one finger still on the screen. + + addHitCircleAt(TouchSource.Touch2); + + beginTouch(TouchSource.Touch1); + assertKeyCounter(1, 0); + checkPressed(OsuAction.LeftButton); + checkPosition(TouchSource.Touch1); + + // hits circle + beginTouch(TouchSource.Touch2); + assertKeyCounter(1, 1); + checkPressed(OsuAction.LeftButton); + checkPressed(OsuAction.RightButton); + checkPosition(TouchSource.Touch2); + + endTouch(TouchSource.Touch1); + checkNotPressed(OsuAction.LeftButton); + + // stream using other two fingers while touch2 tracks + beginTouch(TouchSource.Touch1); + assertKeyCounter(2, 1); + checkPressed(OsuAction.LeftButton); + // right button is automatically released + checkNotPressed(OsuAction.RightButton); + checkPosition(TouchSource.Touch2); + + beginTouch(TouchSource.Touch3); + assertKeyCounter(2, 2); + checkPressed(OsuAction.LeftButton); + checkPressed(OsuAction.RightButton); + checkPosition(TouchSource.Touch2); + + endTouch(TouchSource.Touch1); + checkNotPressed(OsuAction.LeftButton); + + beginTouch(TouchSource.Touch1); + assertKeyCounter(3, 2); + checkPressed(OsuAction.LeftButton); + checkPressed(OsuAction.RightButton); + checkPosition(TouchSource.Touch2); + } + [Test] public void TestNonStreamOverlappingDirectTouchesWithRelease() { From b436b7b99b475348adf7914d27f1e801275c47f9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Jan 2023 17:39:41 +0900 Subject: [PATCH 132/430] Add test coverage of more streaming scenarios --- .../TestSceneTouchInput.cs | 55 ++++++++++++++++++- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs index 4d119bc2ea..22707d218c 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs @@ -191,9 +191,10 @@ namespace osu.Game.Rulesets.Osu.Tests } [Test] - public void TestStreamInputWithInitialTouchDown() + public void TestStreamInputWithInitialTouchDownLeft() { // In this scenario, the user is wanting to use stream input but we start with one finger still on the screen. + // That finger is mapped to a left action. addHitCircleAt(TouchSource.Touch2); @@ -202,7 +203,7 @@ namespace osu.Game.Rulesets.Osu.Tests checkPressed(OsuAction.LeftButton); checkPosition(TouchSource.Touch1); - // hits circle + // hits circle as right action beginTouch(TouchSource.Touch2); assertKeyCounter(1, 1); checkPressed(OsuAction.LeftButton); @@ -236,6 +237,56 @@ namespace osu.Game.Rulesets.Osu.Tests checkPosition(TouchSource.Touch2); } + [Test] + public void TestStreamInputWithInitialTouchDownRight() + { + // In this scenario, the user is wanting to use stream input but we start with one finger still on the screen. + // That finger is mapped to a right action. + + beginTouch(TouchSource.Touch1); + beginTouch(TouchSource.Touch2); + + assertKeyCounter(1, 1); + checkPressed(OsuAction.LeftButton); + checkPressed(OsuAction.RightButton); + + endTouch(TouchSource.Touch1); + + addHitCircleAt(TouchSource.Touch1); + + // hits circle as left action + beginTouch(TouchSource.Touch1); + assertKeyCounter(2, 1); + checkPressed(OsuAction.LeftButton); + checkPressed(OsuAction.RightButton); + checkPosition(TouchSource.Touch1); + + endTouch(TouchSource.Touch2); + + // stream using other two fingers while touch1 tracks + beginTouch(TouchSource.Touch2); + assertKeyCounter(2, 2); + checkPressed(OsuAction.RightButton); + // left button is automatically released + checkNotPressed(OsuAction.LeftButton); + checkPosition(TouchSource.Touch1); + + beginTouch(TouchSource.Touch3); + assertKeyCounter(3, 2); + checkPressed(OsuAction.LeftButton); + checkPressed(OsuAction.RightButton); + checkPosition(TouchSource.Touch1); + + endTouch(TouchSource.Touch2); + checkNotPressed(OsuAction.RightButton); + + beginTouch(TouchSource.Touch2); + assertKeyCounter(3, 3); + checkPressed(OsuAction.LeftButton); + checkPressed(OsuAction.RightButton); + checkPosition(TouchSource.Touch1); + } + [Test] public void TestNonStreamOverlappingDirectTouchesWithRelease() { From b9ed6a7a7c97d014f08b3d39c0906d78f640708f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Jan 2023 17:54:17 +0900 Subject: [PATCH 133/430] Add visual demonstration of streaming that runs a bit faster than other tests --- .../TestSceneTouchInput.cs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs index 22707d218c..4589eb88c0 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs @@ -14,11 +14,13 @@ using osu.Framework.Input.Events; using osu.Framework.Input.States; using osu.Framework.Testing; using osu.Framework.Timing; +using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Configuration; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Rulesets.Osu.UI.Cursor; using osu.Game.Screens.Play; using osu.Game.Tests.Visual; using osuTK; @@ -70,6 +72,10 @@ namespace osu.Game.Rulesets.Osu.Tests Origin = Anchor.CentreLeft, Depth = float.MinValue, X = 100, + }, + new OsuCursorContainer + { + Depth = float.MinValue, } }, } @@ -79,6 +85,40 @@ namespace osu.Game.Rulesets.Osu.Tests }); } + [Test] + public void TestStreamInputVisual() + { + addHitCircleAt(TouchSource.Touch1); + addHitCircleAt(TouchSource.Touch2); + + beginTouch(TouchSource.Touch1); + beginTouch(TouchSource.Touch2); + + endTouch(TouchSource.Touch1); + + int i = 0; + + AddRepeatStep("Alternate", () => + { + TouchSource down = i % 2 == 0 ? TouchSource.Touch3 : TouchSource.Touch4; + TouchSource up = i % 2 == 0 ? TouchSource.Touch4 : TouchSource.Touch3; + + // sometimes the user will end the previous touch before touching again, sometimes not. + if (RNG.NextBool()) + { + InputManager.BeginTouch(new Touch(down, getSanePositionForSource(down))); + InputManager.EndTouch(new Touch(up, getSanePositionForSource(up))); + } + else + { + InputManager.EndTouch(new Touch(up, getSanePositionForSource(up))); + InputManager.BeginTouch(new Touch(down, getSanePositionForSource(down))); + } + + i++; + }, 100); + } + [Test] public void TestSimpleInput() { From 6daa36477942d6179683ec59387ae898f0e0936b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9miah=20D=C3=89COMBE?= Date: Mon, 23 Jan 2023 13:53:31 +0100 Subject: [PATCH 134/430] adding setting to adjust blur of the background of the song select screen --- osu.Game/Configuration/OsuConfigManager.cs | 3 ++ osu.Game/Localisation/UserInterfaceStrings.cs | 6 ++++ .../UserInterface/SongSelectSettings.cs | 5 +++ osu.Game/Screens/Select/SongSelect.cs | 33 +++++++++++++++++-- 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 6cbb677a64..2b7c2102d4 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -60,6 +60,8 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.ToolbarClockDisplayMode, ToolbarClockDisplayMode.Full); + SetDefault(OsuSetting.BeatmapSelectionBlurLevel, 1f, 0, 1f, 0.01f); + // Online settings SetDefault(OsuSetting.Username, string.Empty); SetDefault(OsuSetting.Token, string.Empty); @@ -339,6 +341,7 @@ namespace osu.Game.Configuration ChatDisplayHeight, BeatmapListingCardSize, ToolbarClockDisplayMode, + BeatmapSelectionBlurLevel, Version, ShowFirstRunSetup, ShowConvertedBeatmaps, diff --git a/osu.Game/Localisation/UserInterfaceStrings.cs b/osu.Game/Localisation/UserInterfaceStrings.cs index ea664d7b50..0bf7dae403 100644 --- a/osu.Game/Localisation/UserInterfaceStrings.cs +++ b/osu.Game/Localisation/UserInterfaceStrings.cs @@ -109,6 +109,12 @@ namespace osu.Game.Localisation /// public static LocalisableString ModSelectHotkeyStyle => new TranslatableString(getKey(@"mod_select_hotkey_style"), @"Mod select hotkey style"); + /// + /// "Beatmap selection blur level" + /// + public static LocalisableString BeatmapSelectionBlurLevel => new TranslatableString(getKey(@"beatmap_selection_blur_level"), @"Beatmap selection blur level"); + + /// /// "no limit" /// diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs index 8b5e0b75b7..828119981f 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs @@ -42,6 +42,11 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface LabelText = UserInterfaceStrings.ModSelectHotkeyStyle, Current = config.GetBindable(OsuSetting.ModSelectHotkeyStyle), ClassicDefault = ModSelectHotkeyStyle.Classic + }, + new SettingsSlider + { + LabelText = UserInterfaceStrings.BeatmapSelectionBlurLevel, + Current = config.GetBindable(OsuSetting.BeatmapSelectionBlurLevel) } }; } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 4b3222c14a..bd1498f0dd 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -35,6 +35,7 @@ using osu.Game.Collections; using osu.Game.Graphics.UserInterface; using System.Diagnostics; using osu.Framework.Extensions.ObjectExtensions; +using osu.Game.Configuration; using osu.Game.Screens.Play; using osu.Game.Skinning; @@ -124,9 +125,26 @@ namespace osu.Game.Screens.Select [Resolved] internal IOverlayManager? OverlayManager { get; private set; } - [BackgroundDependencyLoader(true)] - private void load(AudioManager audio, OsuColour colours, ManageCollectionsDialog? manageCollectionsDialog, DifficultyRecommender? recommender) + private Bindable backgroundBlurLevel { get; set; } = new BindableFloat(); + + private void applyBackgroundBlur(float v) { + ApplyToBackground(background => + { + background.IgnoreUserSettings.Value = true; + background.BlurAmount.Value = v * BACKGROUND_BLUR; + }); + } + private void applyBackgroundBlur(ValueChangedEvent v) + { + applyBackgroundBlur(v.NewValue); + } + + [BackgroundDependencyLoader(true)] + private void load(AudioManager audio, OsuColour colours, ManageCollectionsDialog? manageCollectionsDialog, DifficultyRecommender? recommender, OsuConfigManager config) + { + backgroundBlurLevel = config.GetBindable(OsuSetting.BeatmapSelectionBlurLevel); + LoadComponentAsync(Carousel = new BeatmapCarousel { AllowSelection = false, // delay any selection until our bindables are ready to make a good choice. @@ -549,6 +567,9 @@ namespace osu.Game.Screens.Select { base.OnEntering(e); + backgroundBlurLevel.ValueChanged += applyBackgroundBlur; + applyBackgroundBlur(backgroundBlurLevel.Value); + this.FadeInFromZero(250); FilterControl.Activate(); @@ -596,6 +617,8 @@ namespace osu.Game.Screens.Select public override void OnResuming(ScreenTransitionEvent e) { base.OnResuming(e); + backgroundBlurLevel.ValueChanged += applyBackgroundBlur; + applyBackgroundBlur(backgroundBlurLevel.Value); // required due to https://github.com/ppy/osu-framework/issues/3218 ModSelect.SelectedMods.Disabled = false; @@ -641,6 +664,8 @@ namespace osu.Game.Screens.Select // Without this, it's possible for a transfer to happen while we are not the current screen. transferRulesetValue(); + backgroundBlurLevel.ValueChanged -= applyBackgroundBlur; + ModSelect.SelectedMods.UnbindFrom(selectedMods); playExitingTransition(); @@ -649,6 +674,8 @@ namespace osu.Game.Screens.Select public override bool OnExiting(ScreenExitEvent e) { + backgroundBlurLevel.ValueChanged -= applyBackgroundBlur; + if (base.OnExiting(e)) return true; @@ -742,7 +769,7 @@ namespace osu.Game.Screens.Select ApplyToBackground(backgroundModeBeatmap => { backgroundModeBeatmap.Beatmap = beatmap; - backgroundModeBeatmap.BlurAmount.Value = BACKGROUND_BLUR; + backgroundModeBeatmap.BlurAmount.Value = backgroundBlurLevel.Value * BACKGROUND_BLUR; backgroundModeBeatmap.FadeColour(Color4.White, 250); }); From bc94f1b7732dd09d25b660eb150ac38a655f41f6 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Mon, 23 Jan 2023 16:43:38 +0100 Subject: [PATCH 135/430] 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 1f40b2daf6a585278b148c5e91ce4ac314ab3e01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 23 Jan 2023 21:22:18 +0100 Subject: [PATCH 136/430] Clean up xmldocs --- osu.Game/Rulesets/Edit/SelectionBlueprint.cs | 2 +- .../Screens/Edit/Compose/Components/BlueprintContainer.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs index d36ed02210..3c878ffd33 100644 --- a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs +++ b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs @@ -136,7 +136,7 @@ namespace osu.Game.Rulesets.Edit protected virtual Vector2[] ScreenSpaceAdditionalNodes => Array.Empty(); /// - /// The screen-space collection of base points that cause this to be selected via a drag. + /// The screen-space collection of base points on this that other objects can be snapped to. /// The first element of this collection is /// public Vector2[] ScreenSpaceSnapPoints => ScreenSpaceAdditionalNodes.Prepend(ScreenSpaceSelectionPoint).ToArray(); diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index 8cb5a1face..e4e67d10d7 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -513,10 +513,10 @@ namespace osu.Game.Screens.Edit.Compose.Components /// /// Check for positional snap for given blueprint. /// - /// The blueprint to check for snapping - /// Distance travelled since start of dragging action. - /// The selection positions of blueprint before start of dragging action. - /// Whether found object to snap to. + /// The blueprint to check for snapping. + /// Distance travelled since start of dragging action. + /// The snap positions of blueprint before start of dragging action. + /// Whether an object to snap to was found. private bool checkSnappingBlueprintToNearbyObjects(SelectionBlueprint blueprint, Vector2 distanceTravelled, Vector2[] originalPositions) { var currentPositions = blueprint.ScreenSpaceSnapPoints; From a992682276cd49d1e2f71b730ddedf30bf618ece Mon Sep 17 00:00:00 2001 From: Susko3 Date: Mon, 23 Jan 2023 21:46:01 +0100 Subject: [PATCH 137/430] Fix `OsuTouchInputMapper` not handling all touches when using screen scaling --- osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs index c75e179443..6c91d78e23 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs @@ -10,6 +10,7 @@ using osu.Framework.Input; using osu.Framework.Input.Events; using osu.Framework.Input.StateChanges; using osu.Game.Configuration; +using osuTK; namespace osu.Game.Rulesets.Osu.UI { @@ -38,6 +39,8 @@ namespace osu.Game.Rulesets.Osu.UI mouseDisabled = config.GetBindable(OsuSetting.MouseDisableButtons); } + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; + protected override void OnTouchMove(TouchMoveEvent e) { base.OnTouchMove(e); From f13a5465ba38e91be20e4cdb3d811398e01b8430 Mon Sep 17 00:00:00 2001 From: Jeremiah DECOMBE Date: Mon, 23 Jan 2023 23:07:50 +0100 Subject: [PATCH 138/430] variable naming and loc modifications --- osu.Game/Configuration/OsuConfigManager.cs | 4 ++-- osu.Game/Localisation/UserInterfaceStrings.cs | 5 ++--- .../Settings/Sections/UserInterface/SongSelectSettings.cs | 4 ++-- osu.Game/Screens/Select/SongSelect.cs | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 2b7c2102d4..f7b84527b5 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -60,7 +60,7 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.ToolbarClockDisplayMode, ToolbarClockDisplayMode.Full); - SetDefault(OsuSetting.BeatmapSelectionBlurLevel, 1f, 0, 1f, 0.01f); + SetDefault(OsuSetting.BeatmapSelectionBackgoundBlurLevel, 1f, 0, 1f, 0.01f); // Online settings SetDefault(OsuSetting.Username, string.Empty); @@ -341,7 +341,7 @@ namespace osu.Game.Configuration ChatDisplayHeight, BeatmapListingCardSize, ToolbarClockDisplayMode, - BeatmapSelectionBlurLevel, + BeatmapSelectionBackgoundBlurLevel, Version, ShowFirstRunSetup, ShowConvertedBeatmaps, diff --git a/osu.Game/Localisation/UserInterfaceStrings.cs b/osu.Game/Localisation/UserInterfaceStrings.cs index 0bf7dae403..9abb3aaddc 100644 --- a/osu.Game/Localisation/UserInterfaceStrings.cs +++ b/osu.Game/Localisation/UserInterfaceStrings.cs @@ -110,10 +110,9 @@ namespace osu.Game.Localisation public static LocalisableString ModSelectHotkeyStyle => new TranslatableString(getKey(@"mod_select_hotkey_style"), @"Mod select hotkey style"); /// - /// "Beatmap selection blur level" + /// "Song select background blur" /// - public static LocalisableString BeatmapSelectionBlurLevel => new TranslatableString(getKey(@"beatmap_selection_blur_level"), @"Beatmap selection blur level"); - + public static LocalisableString BeatmapSelectionBackgroundBlurLevel => new TranslatableString(getKey(@"beatmap_selection_background_blur_level"), @"Song select background blur"); /// /// "no limit" diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs index 828119981f..f0b2721153 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs @@ -45,8 +45,8 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface }, new SettingsSlider { - LabelText = UserInterfaceStrings.BeatmapSelectionBlurLevel, - Current = config.GetBindable(OsuSetting.BeatmapSelectionBlurLevel) + LabelText = UserInterfaceStrings.BeatmapSelectionBackgroundBlurLevel, + Current = config.GetBindable(OsuSetting.BeatmapSelectionBackgoundBlurLevel) } }; } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index bd1498f0dd..bf6e433a8e 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -143,7 +143,7 @@ namespace osu.Game.Screens.Select [BackgroundDependencyLoader(true)] private void load(AudioManager audio, OsuColour colours, ManageCollectionsDialog? manageCollectionsDialog, DifficultyRecommender? recommender, OsuConfigManager config) { - backgroundBlurLevel = config.GetBindable(OsuSetting.BeatmapSelectionBlurLevel); + backgroundBlurLevel = config.GetBindable(OsuSetting.BeatmapSelectionBackgoundBlurLevel); LoadComponentAsync(Carousel = new BeatmapCarousel { From 26adc28943a802ab924e21f3da02b7a46db083e9 Mon Sep 17 00:00:00 2001 From: Jeremiah DECOMBE Date: Mon, 23 Jan 2023 23:15:37 +0100 Subject: [PATCH 139/430] missing blank line between methods --- osu.Game/Screens/Select/SongSelect.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index bf6e433a8e..c43344d963 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -135,6 +135,7 @@ namespace osu.Game.Screens.Select background.BlurAmount.Value = v * BACKGROUND_BLUR; }); } + private void applyBackgroundBlur(ValueChangedEvent v) { applyBackgroundBlur(v.NewValue); From e6de167adb1c549d060314786730bfef06a243f5 Mon Sep 17 00:00:00 2001 From: naoey Date: Tue, 24 Jan 2023 07:25:13 +0900 Subject: [PATCH 140/430] Revert split and make collections boolean internal to `BeatmapManager` --- .../Beatmaps/WorkingBeatmapManagerTest.cs | 2 +- osu.Game/Beatmaps/BeatmapManager.cs | 26 ++++++------------- osu.Game/Screens/Edit/Editor.cs | 5 +--- osu.Game/Tests/Visual/EditorTestScene.cs | 7 +---- 4 files changed, 11 insertions(+), 29 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs b/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs index 4cd866392b..89b8c8927d 100644 --- a/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs +++ b/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs @@ -124,7 +124,7 @@ namespace osu.Game.Tests.Beatmaps Assert.That(preserveCollection.BeatmapMD5Hashes, Does.Contain(initialHash)); Assert.That(noNewCollection.BeatmapMD5Hashes, Does.Not.Contain(initialHash)); - beatmaps.SaveExistingBeatmap(working.BeatmapInfo, working.GetPlayableBeatmap(new OsuRuleset().RulesetInfo)); + beatmaps.Save(working.BeatmapInfo, working.GetPlayableBeatmap(new OsuRuleset().RulesetInfo)); string finalHash = working.BeatmapInfo.MD5Hash; diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index d644031fe1..fc6d4081e7 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -186,7 +186,7 @@ namespace osu.Game.Beatmaps targetBeatmapSet.Beatmaps.Add(newBeatmap.BeatmapInfo); newBeatmap.BeatmapInfo.BeatmapSet = targetBeatmapSet; - SaveNewBeatmap(newBeatmap.BeatmapInfo, newBeatmap, beatmapSkin); + save(newBeatmap.BeatmapInfo, newBeatmap, beatmapSkin, false); workingBeatmapCache.Invalidate(targetBeatmapSet); return GetWorkingBeatmap(newBeatmap.BeatmapInfo); @@ -286,22 +286,7 @@ namespace osu.Game.Beatmaps /// The to save the content against. The file referenced by will be replaced. /// The content to write. /// The beatmap content to write, null if to be omitted. - public virtual void SaveExistingBeatmap(BeatmapInfo beatmapInfo, IBeatmap beatmapContent, ISkin? beatmapSkin = null) - { - string oldMd5Hash = beatmapInfo.MD5Hash; - - save(beatmapInfo, beatmapContent, beatmapSkin); - - Realm.Write(r => beatmapInfo.TransferCollectionReferences(r, oldMd5Hash)); - } - - /// - /// Saves a new file against a given . - /// - /// The to save the content against. The file referenced by will be replaced. - /// The content to write. - /// The beatmap content to write, null if to be omitted. - public virtual void SaveNewBeatmap(BeatmapInfo beatmapInfo, IBeatmap beatmapContent, ISkin? beatmapSkin = null) + public virtual void Save(BeatmapInfo beatmapInfo, IBeatmap beatmapContent, ISkin? beatmapSkin = null) { save(beatmapInfo, beatmapContent, beatmapSkin); } @@ -414,7 +399,7 @@ namespace osu.Game.Beatmaps setInfo.Status = BeatmapOnlineStatus.LocallyModified; } - private void save(BeatmapInfo beatmapInfo, IBeatmap beatmapContent, ISkin? beatmapSkin) + private void save(BeatmapInfo beatmapInfo, IBeatmap beatmapContent, ISkin? beatmapSkin, bool transferCollections = true) { var setInfo = beatmapInfo.BeatmapSet; Debug.Assert(setInfo != null); @@ -448,6 +433,8 @@ namespace osu.Game.Beatmaps if (existingFileInfo != null) DeleteFile(setInfo, existingFileInfo); + string oldMd5Hash = beatmapInfo.MD5Hash; + beatmapInfo.MD5Hash = stream.ComputeMD5Hash(); beatmapInfo.Hash = stream.ComputeSHA2Hash(); @@ -464,6 +451,9 @@ namespace osu.Game.Beatmaps setInfo.CopyChangesToRealm(liveBeatmapSet); + if (transferCollections) + beatmapInfo.TransferCollectionReferences(r, oldMd5Hash); + ProcessBeatmap?.Invoke((liveBeatmapSet, false)); }); } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 915f3d4a2a..74ea933255 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -429,10 +429,7 @@ namespace osu.Game.Screens.Edit try { // save the loaded beatmap's data stream. - if (isNewBeatmap) - beatmapManager.SaveNewBeatmap(editorBeatmap.BeatmapInfo, editorBeatmap.PlayableBeatmap, editorBeatmap.BeatmapSkin); - else - beatmapManager.SaveExistingBeatmap(editorBeatmap.BeatmapInfo, editorBeatmap.PlayableBeatmap, editorBeatmap.BeatmapSkin); + beatmapManager.Save(editorBeatmap.BeatmapInfo, editorBeatmap.PlayableBeatmap, editorBeatmap.BeatmapSkin); } catch (Exception ex) { diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index 8834911ff5..6e2f1e99cd 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -178,12 +178,7 @@ namespace osu.Game.Tests.Visual => testBeatmapManager.TestBeatmap; } - public override void SaveExistingBeatmap(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) - { - // don't actually care about saving for this context. - } - - public override void SaveNewBeatmap(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) + public override void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) { // don't actually care about saving for this context. } From b573e42cc25575588275eec428366fbffb1cc76b Mon Sep 17 00:00:00 2001 From: Jeremiah DECOMBE Date: Tue, 24 Jan 2023 00:08:11 +0100 Subject: [PATCH 141/430] BeatmapSelectionBackgroundBlurLevel renamed to SongSelectBackgroundBlurLevel --- osu.Game/Configuration/OsuConfigManager.cs | 4 ++-- osu.Game/Localisation/UserInterfaceStrings.cs | 2 +- .../Settings/Sections/UserInterface/SongSelectSettings.cs | 4 ++-- osu.Game/Screens/Select/SongSelect.cs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index f7b84527b5..d26fc2ec43 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -60,7 +60,7 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.ToolbarClockDisplayMode, ToolbarClockDisplayMode.Full); - SetDefault(OsuSetting.BeatmapSelectionBackgoundBlurLevel, 1f, 0, 1f, 0.01f); + SetDefault(OsuSetting.SongSelectBackgoundBlurLevel, 1f, 0, 1f, 0.01f); // Online settings SetDefault(OsuSetting.Username, string.Empty); @@ -341,7 +341,7 @@ namespace osu.Game.Configuration ChatDisplayHeight, BeatmapListingCardSize, ToolbarClockDisplayMode, - BeatmapSelectionBackgoundBlurLevel, + SongSelectBackgoundBlurLevel, Version, ShowFirstRunSetup, ShowConvertedBeatmaps, diff --git a/osu.Game/Localisation/UserInterfaceStrings.cs b/osu.Game/Localisation/UserInterfaceStrings.cs index 9abb3aaddc..5e4c4dc8ed 100644 --- a/osu.Game/Localisation/UserInterfaceStrings.cs +++ b/osu.Game/Localisation/UserInterfaceStrings.cs @@ -112,7 +112,7 @@ namespace osu.Game.Localisation /// /// "Song select background blur" /// - public static LocalisableString BeatmapSelectionBackgroundBlurLevel => new TranslatableString(getKey(@"beatmap_selection_background_blur_level"), @"Song select background blur"); + public static LocalisableString SongSelectBackgroundBlurLevel => new TranslatableString(getKey(@"song_select_background_blur_level"), @"Song select background blur"); /// /// "no limit" diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs index f0b2721153..3228ebfe44 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs @@ -45,8 +45,8 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface }, new SettingsSlider { - LabelText = UserInterfaceStrings.BeatmapSelectionBackgroundBlurLevel, - Current = config.GetBindable(OsuSetting.BeatmapSelectionBackgoundBlurLevel) + LabelText = UserInterfaceStrings.SongSelectBackgroundBlurLevel, + Current = config.GetBindable(OsuSetting.SongSelectBackgoundBlurLevel) } }; } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index c43344d963..b756ac2a98 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -144,7 +144,7 @@ namespace osu.Game.Screens.Select [BackgroundDependencyLoader(true)] private void load(AudioManager audio, OsuColour colours, ManageCollectionsDialog? manageCollectionsDialog, DifficultyRecommender? recommender, OsuConfigManager config) { - backgroundBlurLevel = config.GetBindable(OsuSetting.BeatmapSelectionBackgoundBlurLevel); + backgroundBlurLevel = config.GetBindable(OsuSetting.SongSelectBackgoundBlurLevel); LoadComponentAsync(Carousel = new BeatmapCarousel { From c1876aac887a238d477892c806314f6b50d33adc Mon Sep 17 00:00:00 2001 From: Jeremiah DECOMBE Date: Tue, 24 Jan 2023 00:36:38 +0100 Subject: [PATCH 142/430] removing parameter name abbreviations --- osu.Game/Screens/Select/SongSelect.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index b756ac2a98..eab0620255 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -127,18 +127,18 @@ namespace osu.Game.Screens.Select private Bindable backgroundBlurLevel { get; set; } = new BindableFloat(); - private void applyBackgroundBlur(float v) + private void applyBackgroundBlur(float blurLevel) { ApplyToBackground(background => { background.IgnoreUserSettings.Value = true; - background.BlurAmount.Value = v * BACKGROUND_BLUR; + background.BlurAmount.Value = blurLevel * BACKGROUND_BLUR; }); } - private void applyBackgroundBlur(ValueChangedEvent v) + private void applyBackgroundBlur(ValueChangedEvent blurLevelValueChange) { - applyBackgroundBlur(v.NewValue); + applyBackgroundBlur(blurLevelValueChange.NewValue); } [BackgroundDependencyLoader(true)] From f067a8463150f391437107406fd51cd1ed3db474 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Tue, 24 Jan 2023 00:51:07 +0000 Subject: [PATCH 143/430] TestSceneWikiMarkdowContainer: Update image paths --- .../Online/TestSceneWikiMarkdownContainer.cs | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs index b353123649..c01ce56d55 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs @@ -122,8 +122,8 @@ needs_cleanup: true { AddStep("Add absolute image", () => { - markdownContainer.CurrentPath = "https://dev.ppy.sh"; - markdownContainer.Text = "![intro](/wiki/Interface/img/intro-screen.jpg)"; + markdownContainer.CurrentPath = "https://dev.ppy.sh/wiki/images/Client/Interface/"; + markdownContainer.Text = "![intro](img/intro-screen.jpg)"; }); } @@ -132,7 +132,7 @@ needs_cleanup: true { AddStep("Add relative image", () => { - markdownContainer.CurrentPath = "https://dev.ppy.sh/wiki/Interface/"; + markdownContainer.CurrentPath = "https://dev.ppy.sh/wiki/images/Client/Interface/"; markdownContainer.Text = "![intro](img/intro-screen.jpg)"; }); } @@ -142,7 +142,7 @@ needs_cleanup: true { AddStep("Add paragraph with block image", () => { - markdownContainer.CurrentPath = "https://dev.ppy.sh/wiki/Interface/"; + markdownContainer.CurrentPath = "https://dev.ppy.sh/wiki/images/Client/Interface/"; markdownContainer.Text = @"Line before image ![play menu](img/play-menu.jpg ""Main Menu in osu!"") @@ -156,8 +156,8 @@ Line after image"; { AddStep("Add inline image", () => { - markdownContainer.CurrentPath = "https://dev.ppy.sh"; - markdownContainer.Text = "![osu! mode icon](/wiki/shared/mode/osu.png) osu!"; + markdownContainer.CurrentPath = "https://dev.ppy.sh/wiki/shared/"; + markdownContainer.Text = "![osu! mode icon](mode/osu.png) osu!"; }); } @@ -166,16 +166,16 @@ Line after image"; { AddStep("Add Table", () => { - markdownContainer.CurrentPath = "https://dev.ppy.sh"; + markdownContainer.CurrentPath = "https://dev.ppy.sh/wiki/images/shared/judgement/"; markdownContainer.Text = @" | Image | Name | Effect | | :-: | :-: | :-- | -| ![](/wiki/Skinning/Interface/img/hit300.png ""300"") | 300 | A possible score when tapping a hit circle precisely on time, completing a Slider and keeping the cursor over every tick, or completing a Spinner with the Spinner Metre full. A score of 300 appears in an blue score by default. Scoring nothing except 300s in a beatmap will award the player with the SS or SSH grade. | -| ![](/wiki/Skinning/Interface/img/hit300g.png ""Geki"") | (激) Geki | A term from Ouendan, called Elite Beat! in EBA. Appears when playing the last element in a combo in which the player has scored only 300s. Getting a Geki will give a sizable boost to the Life Bar. By default, it is blue. | -| ![](/wiki/Skinning/Interface/img/hit100.png ""100"") | 100 | A possible score one can get when tapping a Hit Object slightly late or early, completing a Slider and missing a number of ticks, or completing a Spinner with the Spinner Meter almost full. A score of 100 appears in a green score by default. When very skilled players test a beatmap and they get a lot of 100s, this may mean that the beatmap does not have correct timing. | -| ![](/wiki/Skinning/Interface/img/hit300k.png ""300 Katu"") ![](/wiki/Skinning/Interface/img/hit100k.png ""100 Katu"") | (喝) Katu or Katsu | A term from Ouendan, called Beat! in EBA. Appears when playing the last element in a combo in which the player has scored at least one 100, but no 50s or misses. Getting a Katu will give a small boost to the Life Bar. By default, it is coloured green or blue depending on whether the Katu itself is a 100 or a 300. | -| ![](/wiki/Skinning/Interface/img/hit50.png ""50"") | 50 | A possible score one can get when tapping a hit circle rather early or late but not early or late enough to cause a miss, completing a Slider and missing a lot of ticks, or completing a Spinner with the Spinner Metre close to full. A score of 50 appears in a orange score by default. Scoring a 50 in a combo will prevent the appearance of a Katu or a Geki at the combo's end. | -| ![](/wiki/Skinning/Interface/img/hit0.png ""Miss"") | Miss | A possible score one can get when not tapping a hit circle or too early (based on OD and AR, it may *shake* instead), not tapping or holding the Slider at least once, or completing a Spinner with low Spinner Metre fill. Scoring a Miss will reset the current combo to 0 and will prevent the appearance of a Katu or a Geki at the combo's end. | +| ![](osu!/hit300.png ""300"") | 300 | A possible score when tapping a hit circle precisely on time, completing a Slider and keeping the cursor over every tick, or completing a Spinner with the Spinner Metre full. A score of 300 appears in an blue score by default. Scoring nothing except 300s in a beatmap will award the player with the SS or SSH grade. | +| ![](osu!/hit300g.png ""Geki"") | (激) Geki | A term from Ouendan, called Elite Beat! in EBA. Appears when playing the last element in a combo in which the player has scored only 300s. Getting a Geki will give a sizable boost to the Life Bar. By default, it is blue. | +| ![](osu!/hit100.png ""100"") | 100 | A possible score one can get when tapping a Hit Object slightly late or early, completing a Slider and missing a number of ticks, or completing a Spinner with the Spinner Meter almost full. A score of 100 appears in a green score by default. When very skilled players test a beatmap and they get a lot of 100s, this may mean that the beatmap does not have correct timing. | +| ![](osu!/hit300k.png ""300 Katu"") ![](/wiki/Skinning/Interface/img/hit100k.png ""100 Katu"") | (喝) Katu or Katsu | A term from Ouendan, called Beat! in EBA. Appears when playing the last element in a combo in which the player has scored at least one 100, but no 50s or misses. Getting a Katu will give a small boost to the Life Bar. By default, it is coloured green or blue depending on whether the Katu itself is a 100 or a 300. | +| ![](osu!/hit50.png ""50"") | 50 | A possible score one can get when tapping a hit circle rather early or late but not early or late enough to cause a miss, completing a Slider and missing a lot of ticks, or completing a Spinner with the Spinner Metre close to full. A score of 50 appears in a orange score by default. Scoring a 50 in a combo will prevent the appearance of a Katu or a Geki at the combo's end. | +| ![](osu!/hit0.png ""Miss"") | Miss | A possible score one can get when not tapping a hit circle or too early (based on OD and AR, it may *shake* instead), not tapping or holding the Slider at least once, or completing a Spinner with low Spinner Metre fill. Scoring a Miss will reset the current combo to 0 and will prevent the appearance of a Katu or a Geki at the combo's end. | "; }); } @@ -185,7 +185,7 @@ Line after image"; { AddStep("Add image", () => { - markdownContainer.CurrentPath = "https://dev.ppy.sh/wiki/osu!_Program_Files/"; + markdownContainer.CurrentPath = "https://dev.ppy.sh/wiki/images/Client/Program_files/"; markdownContainer.Text = "![](img/file_structure.jpg \"The file structure of osu!'s installation folder, on Windows and macOS\")"; }); From 2454eb8cd9d56f42587e1577ac05824e016ac8f8 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Tue, 24 Jan 2023 00:51:40 +0000 Subject: [PATCH 144/430] TestSceneWikiMarkdownContainer: Add visual test for inline and fenced code syntax --- .../Online/TestSceneWikiMarkdownContainer.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs index c01ce56d55..7b8d04d25f 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs @@ -270,6 +270,30 @@ Phasellus eu nunc nec ligula semper fringilla. Aliquam magna neque, placerat sed }); } + [Test] + public void TestCodeSyntax() + { + AddStep("set content", () => + { + markdownContainer.Text = @" +This is a paragraph containing `inline code` synatax. +Oh wow I do love the `WikiMarkdownContainer`, it is very cool! + +This is a line before the fenced code block: +```csharp +public class WikiMarkdownContainer : MarkdownContainer +{ + public WikiMarkdownContainer() + { + this.foo = bar; + } +} +``` +This is a line after the fenced code block! +"; + }); + } + private partial class TestMarkdownContainer : WikiMarkdownContainer { public LinkInline Link; From 949610c8a4312feece4ddb74b36d6f2dd8cd8595 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Jan 2023 11:06:54 +0900 Subject: [PATCH 145/430] Add commentary as to why `ReceivePositionalInputAt` override is required --- osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs index 6c91d78e23..ffb8c802c7 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs @@ -39,6 +39,7 @@ namespace osu.Game.Rulesets.Osu.UI mouseDisabled = config.GetBindable(OsuSetting.MouseDisableButtons); } + // Required to handle touches outside of the playfield when screen scaling is enabled. public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; protected override void OnTouchMove(TouchMoveEvent e) From 72cfe2ba5a4452ac134060ab90f2dc71ce02cd15 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Jan 2023 12:30:11 +0900 Subject: [PATCH 146/430] Move `private` field up with others --- osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs index 9842e24d05..2e4f983fc4 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs @@ -21,6 +21,8 @@ namespace osu.Game.Rulesets.Osu.UI /// private readonly List trackedTouches = new List(); + private TrackedTouch? positionTrackingTouch; + private readonly OsuInputManager osuInputManager; private Bindable mouseDisabled = null!; @@ -44,8 +46,6 @@ namespace osu.Game.Rulesets.Osu.UI handleTouchMovement(e); } - private TrackedTouch? positionTrackingTouch; - protected override bool OnTouchDown(TouchDownEvent e) { OsuAction action = trackedTouches.Any(t => t.Action == OsuAction.LeftButton) From 04995b66da5f6abb71ae51eef0628915c1b7df41 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 24 Jan 2023 07:09:25 +0300 Subject: [PATCH 147/430] Add seed slider to Triangles test sceen --- osu.Game.Tests/Visual/Background/TestSceneTrianglesBackground.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/Background/TestSceneTrianglesBackground.cs b/osu.Game.Tests/Visual/Background/TestSceneTrianglesBackground.cs index d3cdf928e8..8a5489f476 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneTrianglesBackground.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneTrianglesBackground.cs @@ -35,6 +35,7 @@ namespace osu.Game.Tests.Visual.Background base.LoadComplete(); AddSliderStep("Triangle scale", 0f, 10f, 1f, s => triangles.TriangleScale = s); + AddSliderStep("Seed", 0, 1000, 0, s => triangles.Reset(s)); } } } From fc558278ccc164d54dcd4d8adf5989e1399f705a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Jan 2023 13:37:12 +0900 Subject: [PATCH 148/430] Fix touch input handler settings not matching search for "touchscreen" --- osu.Game/OsuGameBase.cs | 4 +- .../Settings/Sections/Input/TouchSettings.cs | 40 +++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 osu.Game/Overlays/Settings/Sections/Input/TouchSettings.cs diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index a38aa19cef..cf58d07b9e 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -556,8 +556,8 @@ namespace osu.Game case JoystickHandler jh: return new JoystickSettings(jh); - case TouchHandler: - return new InputSection.HandlerSection(handler); + case TouchHandler th: + return new TouchSettings(th); } } diff --git a/osu.Game/Overlays/Settings/Sections/Input/TouchSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TouchSettings.cs new file mode 100644 index 0000000000..8d1b12d5b2 --- /dev/null +++ b/osu.Game/Overlays/Settings/Sections/Input/TouchSettings.cs @@ -0,0 +1,40 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Input.Handlers.Touch; +using osu.Framework.Localisation; +using osu.Game.Localisation; + +namespace osu.Game.Overlays.Settings.Sections.Input +{ + public partial class TouchSettings : SettingsSubsection + { + private readonly TouchHandler handler; + + public TouchSettings(TouchHandler handler) + { + this.handler = handler; + } + + [BackgroundDependencyLoader] + private void load() + { + Children = new Drawable[] + { + new SettingsCheckbox + { + LabelText = CommonStrings.Enabled, + Current = handler.Enabled + }, + }; + } + + public override IEnumerable FilterTerms => base.FilterTerms.Concat(new LocalisableString[] { @"touchscreen" }); + + protected override LocalisableString Header => handler.Description; + } +} From 04c96355cb682610e14be0b9731b4fba3489f685 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 24 Jan 2023 07:38:42 +0300 Subject: [PATCH 149/430] Use TriangleBorder shader to draw triangles --- osu.Game/Graphics/Backgrounds/Triangles.cs | 40 ++++++++++------------ 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs index 94397f7ffb..d9dff1574f 100644 --- a/osu.Game/Graphics/Backgrounds/Triangles.cs +++ b/osu.Game/Graphics/Backgrounds/Triangles.cs @@ -31,12 +31,6 @@ namespace osu.Game.Graphics.Backgrounds /// private const float equilateral_triangle_ratio = 0.866f; - /// - /// How many screen-space pixels are smoothed over. - /// Same behavior as Sprite's EdgeSmoothness. - /// - private const float edge_smoothness = 1; - private Color4 colourLight = Color4.White; public Color4 ColourLight @@ -115,7 +109,7 @@ namespace osu.Game.Graphics.Backgrounds private void load(IRenderer renderer, ShaderManager shaders) { texture = renderer.WhitePixel; - shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE); + shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, "TriangleBorder"); } protected override void LoadComplete() @@ -252,14 +246,17 @@ namespace osu.Game.Graphics.Backgrounds private class TrianglesDrawNode : DrawNode { + private float fill = 1f; + protected new Triangles Source => (Triangles)base.Source; private IShader shader; private Texture texture; private readonly List parts = new List(); - private Vector2 size; + private readonly Vector2 triangleSize = new Vector2(1f, equilateral_triangle_ratio) * triangle_size; + private Vector2 size; private IVertexBatch vertexBatch; public TrianglesDrawNode(Triangles source) @@ -290,29 +287,28 @@ namespace osu.Game.Graphics.Backgrounds } shader.Bind(); - - Vector2 localInflationAmount = edge_smoothness * DrawInfo.MatrixInverse.ExtractScale().Xy; + shader.GetUniform("thickness").UpdateValue(ref fill); foreach (TriangleParticle particle in parts) { - var offset = triangle_size * new Vector2(particle.Scale * 0.5f, particle.Scale * equilateral_triangle_ratio); + Vector2 relativeSize = Vector2.Divide(triangleSize * particle.Scale, size); - var triangle = new Triangle( - Vector2Extensions.Transform(particle.Position * size, DrawInfo.Matrix), - Vector2Extensions.Transform(particle.Position * size + offset, DrawInfo.Matrix), - Vector2Extensions.Transform(particle.Position * size + new Vector2(-offset.X, offset.Y), DrawInfo.Matrix) + Vector2 topLeft = particle.Position - new Vector2(relativeSize.X * 0.5f, 0f); + Vector2 topRight = topLeft + new Vector2(relativeSize.X, 0f); + Vector2 bottomLeft = topLeft + new Vector2(0f, relativeSize.Y); + Vector2 bottomRight = bottomLeft + new Vector2(relativeSize.X, 0f); + + var drawQuad = new Quad( + Vector2Extensions.Transform(topLeft * size, DrawInfo.Matrix), + Vector2Extensions.Transform(topRight * size, DrawInfo.Matrix), + Vector2Extensions.Transform(bottomLeft * size, DrawInfo.Matrix), + Vector2Extensions.Transform(bottomRight * size, DrawInfo.Matrix) ); ColourInfo colourInfo = DrawColourInfo.Colour; colourInfo.ApplyChild(particle.Colour); - renderer.DrawTriangle( - texture, - triangle, - colourInfo, - null, - vertexBatch.AddAction, - Vector2.Divide(localInflationAmount, new Vector2(2 * offset.X, offset.Y))); + renderer.DrawQuad(texture, drawQuad, colourInfo, vertexAction: vertexBatch.AddAction); } shader.Unbind(); From bb15ee50e066b161437c88bf5ecbb0bc18587141 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Jan 2023 13:52:59 +0900 Subject: [PATCH 150/430] Fix beatmap leaderboard potentially showing incorrect leaderboard --- osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index c419501add..5c720c8491 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -104,6 +104,9 @@ namespace osu.Game.Screens.Select.Leaderboards protected override APIRequest? FetchScores(CancellationToken cancellationToken) { + scoreRetrievalRequest?.Cancel(); + scoreRetrievalRequest = null; + var fetchBeatmapInfo = BeatmapInfo; if (fetchBeatmapInfo == null) @@ -152,8 +155,6 @@ namespace osu.Game.Screens.Select.Leaderboards else if (filterMods) requestMods = mods.Value; - scoreRetrievalRequest?.Cancel(); - var newRequest = new GetScoresRequest(fetchBeatmapInfo, fetchRuleset, Scope, requestMods); newRequest.Success += response => Schedule(() => { From b46ef67a14c68a48d210e206db542dc90cff20ee Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Tue, 24 Jan 2023 00:31:46 -0500 Subject: [PATCH 151/430] increase min minimum accuracy to 60% --- osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs index e18164db89..59fbfe49b6 100644 --- a/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs +++ b/osu.Game/Rulesets/Mods/ModAccuracyChallenge.cs @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Mods [SettingSource("Minimum accuracy", "Trigger a failure if your accuracy goes below this value.", SettingControlType = typeof(SettingsSlider))] public BindableNumber MinimumAccuracy { get; } = new BindableDouble { - MinValue = 0.01, + MinValue = 0.60, MaxValue = 0.99, Precision = 0.01, Default = 0.9, From d783998c81f58bd1548e4f6569aca886868845e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9miah=20D=C3=89COMBE?= Date: Tue, 24 Jan 2023 09:09:05 +0100 Subject: [PATCH 152/430] using BindValueChanged and IsCurrentScreen for setting binding --- osu.Game/Screens/Select/SongSelect.cs | 34 +++++++++------------------ 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index eab0620255..dbd948ff86 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -127,24 +127,21 @@ namespace osu.Game.Screens.Select private Bindable backgroundBlurLevel { get; set; } = new BindableFloat(); - private void applyBackgroundBlur(float blurLevel) - { - ApplyToBackground(background => - { - background.IgnoreUserSettings.Value = true; - background.BlurAmount.Value = blurLevel * BACKGROUND_BLUR; - }); - } - - private void applyBackgroundBlur(ValueChangedEvent blurLevelValueChange) - { - applyBackgroundBlur(blurLevelValueChange.NewValue); - } - [BackgroundDependencyLoader(true)] private void load(AudioManager audio, OsuColour colours, ManageCollectionsDialog? manageCollectionsDialog, DifficultyRecommender? recommender, OsuConfigManager config) { backgroundBlurLevel = config.GetBindable(OsuSetting.SongSelectBackgoundBlurLevel); + backgroundBlurLevel.BindValueChanged(e => + { + if (this.IsCurrentScreen()) + { + ApplyToBackground(background => + { + background.IgnoreUserSettings.Value = true; + background.BlurAmount.Value = e.NewValue * BACKGROUND_BLUR; + }); + } + }, true); LoadComponentAsync(Carousel = new BeatmapCarousel { @@ -568,9 +565,6 @@ namespace osu.Game.Screens.Select { base.OnEntering(e); - backgroundBlurLevel.ValueChanged += applyBackgroundBlur; - applyBackgroundBlur(backgroundBlurLevel.Value); - this.FadeInFromZero(250); FilterControl.Activate(); @@ -618,8 +612,6 @@ namespace osu.Game.Screens.Select public override void OnResuming(ScreenTransitionEvent e) { base.OnResuming(e); - backgroundBlurLevel.ValueChanged += applyBackgroundBlur; - applyBackgroundBlur(backgroundBlurLevel.Value); // required due to https://github.com/ppy/osu-framework/issues/3218 ModSelect.SelectedMods.Disabled = false; @@ -665,8 +657,6 @@ namespace osu.Game.Screens.Select // Without this, it's possible for a transfer to happen while we are not the current screen. transferRulesetValue(); - backgroundBlurLevel.ValueChanged -= applyBackgroundBlur; - ModSelect.SelectedMods.UnbindFrom(selectedMods); playExitingTransition(); @@ -675,8 +665,6 @@ namespace osu.Game.Screens.Select public override bool OnExiting(ScreenExitEvent e) { - backgroundBlurLevel.ValueChanged -= applyBackgroundBlur; - if (base.OnExiting(e)) return true; From 7ca2a431e655bea849184e937819b384eb9cdfa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9miah=20D=C3=89COMBE?= Date: Tue, 24 Jan 2023 09:19:53 +0100 Subject: [PATCH 153/430] changing song select background blur setting to boolean --- osu.Game/Configuration/OsuConfigManager.cs | 4 ++-- .../Settings/Sections/UserInterface/SongSelectSettings.cs | 4 ++-- osu.Game/Screens/Select/SongSelect.cs | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index d26fc2ec43..fff5dc62c6 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -60,7 +60,7 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.ToolbarClockDisplayMode, ToolbarClockDisplayMode.Full); - SetDefault(OsuSetting.SongSelectBackgoundBlurLevel, 1f, 0, 1f, 0.01f); + SetDefault(OsuSetting.SongSelectBackgoundBlur, true); // Online settings SetDefault(OsuSetting.Username, string.Empty); @@ -341,7 +341,7 @@ namespace osu.Game.Configuration ChatDisplayHeight, BeatmapListingCardSize, ToolbarClockDisplayMode, - SongSelectBackgoundBlurLevel, + SongSelectBackgoundBlur, Version, ShowFirstRunSetup, ShowConvertedBeatmaps, diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs index 3228ebfe44..ab5a3a1280 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs @@ -43,10 +43,10 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface Current = config.GetBindable(OsuSetting.ModSelectHotkeyStyle), ClassicDefault = ModSelectHotkeyStyle.Classic }, - new SettingsSlider + new SettingsCheckbox { LabelText = UserInterfaceStrings.SongSelectBackgroundBlurLevel, - Current = config.GetBindable(OsuSetting.SongSelectBackgoundBlurLevel) + Current = config.GetBindable(OsuSetting.SongSelectBackgoundBlur) } }; } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index dbd948ff86..bbb88052aa 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -125,12 +125,12 @@ namespace osu.Game.Screens.Select [Resolved] internal IOverlayManager? OverlayManager { get; private set; } - private Bindable backgroundBlurLevel { get; set; } = new BindableFloat(); + private Bindable backgroundBlurLevel { get; set; } = new BindableBool(); [BackgroundDependencyLoader(true)] private void load(AudioManager audio, OsuColour colours, ManageCollectionsDialog? manageCollectionsDialog, DifficultyRecommender? recommender, OsuConfigManager config) { - backgroundBlurLevel = config.GetBindable(OsuSetting.SongSelectBackgoundBlurLevel); + backgroundBlurLevel = config.GetBindable(OsuSetting.SongSelectBackgoundBlur); backgroundBlurLevel.BindValueChanged(e => { if (this.IsCurrentScreen()) @@ -138,7 +138,7 @@ namespace osu.Game.Screens.Select ApplyToBackground(background => { background.IgnoreUserSettings.Value = true; - background.BlurAmount.Value = e.NewValue * BACKGROUND_BLUR; + background.BlurAmount.Value = e.NewValue ? BACKGROUND_BLUR : 0; }); } }, true); @@ -758,7 +758,7 @@ namespace osu.Game.Screens.Select ApplyToBackground(backgroundModeBeatmap => { backgroundModeBeatmap.Beatmap = beatmap; - backgroundModeBeatmap.BlurAmount.Value = backgroundBlurLevel.Value * BACKGROUND_BLUR; + backgroundModeBeatmap.BlurAmount.Value = backgroundBlurLevel.Value ? BACKGROUND_BLUR : 0f; backgroundModeBeatmap.FadeColour(Color4.White, 250); }); From df895c4fd685d3c2d61ddfae3edfb17282b785db Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 24 Jan 2023 00:21:39 -0800 Subject: [PATCH 154/430] Always make settings footer build display clickable --- osu.Game/Overlays/Settings/SettingsFooter.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Settings/SettingsFooter.cs b/osu.Game/Overlays/Settings/SettingsFooter.cs index 62933ed556..9ab0fa7ad8 100644 --- a/osu.Game/Overlays/Settings/SettingsFooter.cs +++ b/osu.Game/Overlays/Settings/SettingsFooter.cs @@ -49,7 +49,7 @@ namespace osu.Game.Overlays.Settings Text = game.Name, Font = OsuFont.GetFont(size: 18, weight: FontWeight.Bold), }, - new BuildDisplay(game.Version, DebugUtils.IsDebugBuild) + new BuildDisplay(game.Version) { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, @@ -81,15 +81,13 @@ namespace osu.Game.Overlays.Settings private partial class BuildDisplay : OsuAnimatedButton { private readonly string version; - private readonly bool isDebug; [Resolved] private OsuColour colours { get; set; } - public BuildDisplay(string version, bool isDebug) + public BuildDisplay(string version) { this.version = version; - this.isDebug = isDebug; Content.RelativeSizeAxes = Axes.Y; Content.AutoSizeAxes = AutoSizeAxes = Axes.X; @@ -99,8 +97,7 @@ namespace osu.Game.Overlays.Settings [BackgroundDependencyLoader(true)] private void load(ChangelogOverlay changelog) { - if (!isDebug) - Action = () => changelog?.ShowBuild(OsuGameBase.CLIENT_STREAM_NAME, version); + Action = () => changelog?.ShowBuild(OsuGameBase.CLIENT_STREAM_NAME, version); Add(new OsuSpriteText { @@ -110,7 +107,7 @@ namespace osu.Game.Overlays.Settings Anchor = Anchor.Centre, Origin = Anchor.Centre, Padding = new MarginPadding(5), - Colour = isDebug ? colours.Red : Color4.White, + Colour = DebugUtils.IsDebugBuild ? colours.Red : Color4.White, }); } } From c6bf755e688e149f6406b0fc57dcfb56df1297e7 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 24 Jan 2023 00:22:29 -0800 Subject: [PATCH 155/430] Remove `IsPresent` override from `ChangelogOverlay` --- osu.Game/Overlays/ChangelogOverlay.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Overlays/ChangelogOverlay.cs b/osu.Game/Overlays/ChangelogOverlay.cs index 671d649dcf..34472cb7cd 100644 --- a/osu.Game/Overlays/ChangelogOverlay.cs +++ b/osu.Game/Overlays/ChangelogOverlay.cs @@ -22,8 +22,6 @@ namespace osu.Game.Overlays { public partial class ChangelogOverlay : OnlineOverlay { - public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks; - public readonly Bindable Current = new Bindable(); private List builds; From 3a47be6e002eecbea52c443741fad75041261f93 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Jan 2023 17:43:14 +0900 Subject: [PATCH 156/430] Fix argon hit circles occasionally going missing during editor seeking --- .../Skinning/Argon/ArgonMainCirclePiece.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs index db458ec48a..a62efa96bf 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs @@ -64,21 +64,18 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon outerGradient = new Circle // renders the outer bright gradient { Size = new Vector2(OUTER_GRADIENT_SIZE), - Alpha = 1, Anchor = Anchor.Centre, Origin = Anchor.Centre, }, innerGradient = new Circle // renders the inner bright gradient { Size = new Vector2(INNER_GRADIENT_SIZE), - Alpha = 1, Anchor = Anchor.Centre, Origin = Anchor.Centre, }, innerFill = new Circle // renders the inner dark fill { Size = new Vector2(INNER_FILL_SIZE), - Alpha = 1, Anchor = Anchor.Centre, Origin = Anchor.Centre, }, @@ -123,14 +120,18 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon // Accent colour may be changed many times during a paused gameplay state. // Schedule the change to avoid transforms piling up. - Scheduler.AddOnce(updateStateTransforms); + Scheduler.AddOnce(() => + { + updateStateTransforms(drawableObject, drawableObject.State.Value); + + ApplyTransformsAt(double.MinValue, true); + ClearTransformsAfter(double.MinValue, true); + }); }, true); drawableObject.ApplyCustomUpdateState += updateStateTransforms; } - private void updateStateTransforms() => updateStateTransforms(drawableObject, drawableObject.State.Value); - private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) { using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime)) From e0a7559d851fca88f92d8866cb54a08f8cd0f6b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9miah=20D=C3=89COMBE?= Date: Tue, 24 Jan 2023 09:55:08 +0100 Subject: [PATCH 157/430] variable naming + loc --- osu.Game/Localisation/UserInterfaceStrings.cs | 4 ++-- .../Settings/Sections/UserInterface/SongSelectSettings.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Localisation/UserInterfaceStrings.cs b/osu.Game/Localisation/UserInterfaceStrings.cs index 5e4c4dc8ed..fb9eeeb3de 100644 --- a/osu.Game/Localisation/UserInterfaceStrings.cs +++ b/osu.Game/Localisation/UserInterfaceStrings.cs @@ -110,9 +110,9 @@ namespace osu.Game.Localisation public static LocalisableString ModSelectHotkeyStyle => new TranslatableString(getKey(@"mod_select_hotkey_style"), @"Mod select hotkey style"); /// - /// "Song select background blur" + /// "Background blur" /// - public static LocalisableString SongSelectBackgroundBlurLevel => new TranslatableString(getKey(@"song_select_background_blur_level"), @"Song select background blur"); + public static LocalisableString BackgroundBlurLevel => new TranslatableString(getKey(@"background_blur_level"), @"Background blur"); /// /// "no limit" diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs index ab5a3a1280..11f7976842 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs @@ -45,7 +45,7 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface }, new SettingsCheckbox { - LabelText = UserInterfaceStrings.SongSelectBackgroundBlurLevel, + LabelText = UserInterfaceStrings.BackgroundBlurLevel, Current = config.GetBindable(OsuSetting.SongSelectBackgoundBlur) } }; diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index bbb88052aa..505f932bff 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -125,13 +125,13 @@ namespace osu.Game.Screens.Select [Resolved] internal IOverlayManager? OverlayManager { get; private set; } - private Bindable backgroundBlurLevel { get; set; } = new BindableBool(); + private Bindable configBackgroundBlur { get; set; } = new BindableBool(); [BackgroundDependencyLoader(true)] private void load(AudioManager audio, OsuColour colours, ManageCollectionsDialog? manageCollectionsDialog, DifficultyRecommender? recommender, OsuConfigManager config) { - backgroundBlurLevel = config.GetBindable(OsuSetting.SongSelectBackgoundBlur); - backgroundBlurLevel.BindValueChanged(e => + configBackgroundBlur = config.GetBindable(OsuSetting.SongSelectBackgoundBlur); + configBackgroundBlur.BindValueChanged(e => { if (this.IsCurrentScreen()) { @@ -758,7 +758,7 @@ namespace osu.Game.Screens.Select ApplyToBackground(backgroundModeBeatmap => { backgroundModeBeatmap.Beatmap = beatmap; - backgroundModeBeatmap.BlurAmount.Value = backgroundBlurLevel.Value ? BACKGROUND_BLUR : 0f; + backgroundModeBeatmap.BlurAmount.Value = configBackgroundBlur.Value ? BACKGROUND_BLUR : 0f; backgroundModeBeatmap.FadeColour(Color4.White, 250); }); From b9291cb116577b4549aa8b6177e4ec3da5018ffb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Jan 2023 17:59:25 +0900 Subject: [PATCH 158/430] Change some order and assert for positive visibility before scheduling an operation in changelog overlay --- osu.Game/Overlays/ChangelogOverlay.cs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/ChangelogOverlay.cs b/osu.Game/Overlays/ChangelogOverlay.cs index 34472cb7cd..4cc38c41e4 100644 --- a/osu.Game/Overlays/ChangelogOverlay.cs +++ b/osu.Game/Overlays/ChangelogOverlay.cs @@ -5,12 +5,14 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; using osu.Game.Input.Bindings; using osu.Game.Online.API.Requests; @@ -79,6 +81,8 @@ namespace osu.Game.Overlays ArgumentNullException.ThrowIfNull(updateStream); ArgumentNullException.ThrowIfNull(version); + Show(); + performAfterFetch(() => { var build = builds.Find(b => b.Version == version && b.UpdateStream.Name == updateStream) @@ -87,8 +91,6 @@ namespace osu.Game.Overlays if (build != null) ShowBuild(build); }); - - Show(); } public override bool OnPressed(KeyBindingPressEvent e) @@ -125,11 +127,16 @@ namespace osu.Game.Overlays private Task initialFetchTask; - private void performAfterFetch(Action action) => Schedule(() => + private void performAfterFetch(Action action) { - fetchListing()?.ContinueWith(_ => - Schedule(action), TaskContinuationOptions.OnlyOnRanToCompletion); - }); + Debug.Assert(State.Value == Visibility.Visible); + + Schedule(() => + { + fetchListing()?.ContinueWith(_ => + Schedule(action), TaskContinuationOptions.OnlyOnRanToCompletion); + }); + } private Task fetchListing() { From acb42f7d1265fe8ab7a72d302a4af6d7e12d7bb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9miah=20D=C3=89COMBE?= Date: Tue, 24 Jan 2023 10:18:00 +0100 Subject: [PATCH 159/430] reusing gameplay background blur loc song select background blur --- .../Settings/Sections/UserInterface/SongSelectSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs index 11f7976842..d40d24a528 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs @@ -45,7 +45,7 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface }, new SettingsCheckbox { - LabelText = UserInterfaceStrings.BackgroundBlurLevel, + LabelText = GameplaySettingsStrings.BackgroundBlur, Current = config.GetBindable(OsuSetting.SongSelectBackgoundBlur) } }; From c991aa5ca4f1a947c92e637228ee28c2b865e87b Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Tue, 24 Jan 2023 22:01:53 +0000 Subject: [PATCH 160/430] TestSceneWikiMarkdownContainer: Revert CurrentPath changes and update markdown img links only --- .../Online/TestSceneWikiMarkdownContainer.cs | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs index 7b8d04d25f..ab9fae5d2c 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs @@ -122,8 +122,8 @@ needs_cleanup: true { AddStep("Add absolute image", () => { - markdownContainer.CurrentPath = "https://dev.ppy.sh/wiki/images/Client/Interface/"; - markdownContainer.Text = "![intro](img/intro-screen.jpg)"; + markdownContainer.CurrentPath = "https://dev.ppy.sh"; + markdownContainer.Text = "![intro](wiki/images/Client/Interface/img/intro-screen.jpg)"; }); } @@ -132,8 +132,8 @@ needs_cleanup: true { AddStep("Add relative image", () => { - markdownContainer.CurrentPath = "https://dev.ppy.sh/wiki/images/Client/Interface/"; - markdownContainer.Text = "![intro](img/intro-screen.jpg)"; + markdownContainer.CurrentPath = "https://dev.ppy.sh/wiki/Interface/"; + markdownContainer.Text = "![intro](../images/Client/Interface/img/intro-screen.jpg)"; }); } @@ -142,10 +142,10 @@ needs_cleanup: true { AddStep("Add paragraph with block image", () => { - markdownContainer.CurrentPath = "https://dev.ppy.sh/wiki/images/Client/Interface/"; + markdownContainer.CurrentPath = "https://dev.ppy.sh/wiki/Interface/"; markdownContainer.Text = @"Line before image -![play menu](img/play-menu.jpg ""Main Menu in osu!"") +![play menu](../images/Client/Interface/img/play-menu.jpg ""Main Menu in osu!"") Line after image"; }); @@ -156,8 +156,8 @@ Line after image"; { AddStep("Add inline image", () => { - markdownContainer.CurrentPath = "https://dev.ppy.sh/wiki/shared/"; - markdownContainer.Text = "![osu! mode icon](mode/osu.png) osu!"; + markdownContainer.CurrentPath = "https://dev.ppy.sh"; + markdownContainer.Text = "![osu! mode icon](wiki/shared/mode/osu.png) osu!"; }); } @@ -166,16 +166,16 @@ Line after image"; { AddStep("Add Table", () => { - markdownContainer.CurrentPath = "https://dev.ppy.sh/wiki/images/shared/judgement/"; + markdownContainer.CurrentPath = "https://dev.ppy.sh"; markdownContainer.Text = @" | Image | Name | Effect | | :-: | :-: | :-- | -| ![](osu!/hit300.png ""300"") | 300 | A possible score when tapping a hit circle precisely on time, completing a Slider and keeping the cursor over every tick, or completing a Spinner with the Spinner Metre full. A score of 300 appears in an blue score by default. Scoring nothing except 300s in a beatmap will award the player with the SS or SSH grade. | -| ![](osu!/hit300g.png ""Geki"") | (激) Geki | A term from Ouendan, called Elite Beat! in EBA. Appears when playing the last element in a combo in which the player has scored only 300s. Getting a Geki will give a sizable boost to the Life Bar. By default, it is blue. | -| ![](osu!/hit100.png ""100"") | 100 | A possible score one can get when tapping a Hit Object slightly late or early, completing a Slider and missing a number of ticks, or completing a Spinner with the Spinner Meter almost full. A score of 100 appears in a green score by default. When very skilled players test a beatmap and they get a lot of 100s, this may mean that the beatmap does not have correct timing. | -| ![](osu!/hit300k.png ""300 Katu"") ![](/wiki/Skinning/Interface/img/hit100k.png ""100 Katu"") | (喝) Katu or Katsu | A term from Ouendan, called Beat! in EBA. Appears when playing the last element in a combo in which the player has scored at least one 100, but no 50s or misses. Getting a Katu will give a small boost to the Life Bar. By default, it is coloured green or blue depending on whether the Katu itself is a 100 or a 300. | -| ![](osu!/hit50.png ""50"") | 50 | A possible score one can get when tapping a hit circle rather early or late but not early or late enough to cause a miss, completing a Slider and missing a lot of ticks, or completing a Spinner with the Spinner Metre close to full. A score of 50 appears in a orange score by default. Scoring a 50 in a combo will prevent the appearance of a Katu or a Geki at the combo's end. | -| ![](osu!/hit0.png ""Miss"") | Miss | A possible score one can get when not tapping a hit circle or too early (based on OD and AR, it may *shake* instead), not tapping or holding the Slider at least once, or completing a Spinner with low Spinner Metre fill. Scoring a Miss will reset the current combo to 0 and will prevent the appearance of a Katu or a Geki at the combo's end. | +| ![](wiki/images/shared/judgement/osu!/hit300.png ""300"") | 300 | A possible score when tapping a hit circle precisely on time, completing a Slider and keeping the cursor over every tick, or completing a Spinner with the Spinner Metre full. A score of 300 appears in an blue score by default. Scoring nothing except 300s in a beatmap will award the player with the SS or SSH grade. | +| ![](wiki/images/shared/judgement/osu!/hit300g.png ""Geki"") | (激) Geki | A term from Ouendan, called Elite Beat! in EBA. Appears when playing the last element in a combo in which the player has scored only 300s. Getting a Geki will give a sizable boost to the Life Bar. By default, it is blue. | +| ![](wiki/images/shared/judgement/osu!/hit100.png ""100"") | 100 | A possible score one can get when tapping a Hit Object slightly late or early, completing a Slider and missing a number of ticks, or completing a Spinner with the Spinner Meter almost full. A score of 100 appears in a green score by default. When very skilled players test a beatmap and they get a lot of 100s, this may mean that the beatmap does not have correct timing. | +| ![](wiki/images/shared/judgement/osu!/hit300k.png ""300 Katu"") ![](/wiki/Skinning/Interface/img/hit100k.png ""100 Katu"") | (喝) Katu or Katsu | A term from Ouendan, called Beat! in EBA. Appears when playing the last element in a combo in which the player has scored at least one 100, but no 50s or misses. Getting a Katu will give a small boost to the Life Bar. By default, it is coloured green or blue depending on whether the Katu itself is a 100 or a 300. | +| ![](wiki/images/shared/judgement/osu!/hit50.png ""50"") | 50 | A possible score one can get when tapping a hit circle rather early or late but not early or late enough to cause a miss, completing a Slider and missing a lot of ticks, or completing a Spinner with the Spinner Metre close to full. A score of 50 appears in a orange score by default. Scoring a 50 in a combo will prevent the appearance of a Katu or a Geki at the combo's end. | +| ![](wiki/images/shared/judgement/osu!/hit0.png ""Miss"") | Miss | A possible score one can get when not tapping a hit circle or too early (based on OD and AR, it may *shake* instead), not tapping or holding the Slider at least once, or completing a Spinner with low Spinner Metre fill. Scoring a Miss will reset the current combo to 0 and will prevent the appearance of a Katu or a Geki at the combo's end. | "; }); } @@ -185,8 +185,8 @@ Line after image"; { AddStep("Add image", () => { - markdownContainer.CurrentPath = "https://dev.ppy.sh/wiki/images/Client/Program_files/"; - markdownContainer.Text = "![](img/file_structure.jpg \"The file structure of osu!'s installation folder, on Windows and macOS\")"; + markdownContainer.CurrentPath = "https://dev.ppy.sh/wiki/osu!_Program_Files/"; + markdownContainer.Text = "![](../images/Client/Program_files/img/file_structure.jpg \"The file structure of osu!'s installation folder, on Windows and macOS\")"; }); AddUntilStep("Wait image to load", () => markdownContainer.ChildrenOfType().First().DelayedLoadCompleted); From ff22a91d5287aaf19b7a8f5f80dfba2e7b75b92f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 31 Dec 2022 19:36:17 +0100 Subject: [PATCH 161/430] Move user cover lower down --- .../Profile/Header/TopHeaderContainer.cs | 165 +++++++++++------- osu.Game/Overlays/Profile/ProfileHeader.cs | 35 +--- 2 files changed, 99 insertions(+), 101 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs index 1fe39cb570..270be7cdf4 100644 --- a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs @@ -14,6 +14,7 @@ using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Overlays.Profile.Header.Components; +using osu.Game.Users; using osu.Game.Users.Drawables; using osuTK; @@ -28,6 +29,7 @@ namespace osu.Game.Overlays.Profile.Header [Resolved] private IAPIProvider api { get; set; } = null!; + private UserCoverBackground cover = null!; private SupporterIcon supporterTag = null!; private UpdateableAvatar avatar = null!; private OsuSpriteText usernameText = null!; @@ -40,7 +42,8 @@ namespace osu.Game.Overlays.Profile.Header [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) { - Height = 150; + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; InternalChildren = new Drawable[] { @@ -51,52 +54,73 @@ namespace osu.Game.Overlays.Profile.Header }, new FillFlowContainer { - Direction = FillDirection.Horizontal, - Margin = new MarginPadding { Left = UserProfileOverlay.CONTENT_X_MARGIN }, - Height = avatar_size, - AutoSizeAxes = Axes.X, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, Children = new Drawable[] { - avatar = new UpdateableAvatar(isInteractive: false, showGuestOnNull: false) + cover = new ProfileCoverBackground { - Size = new Vector2(avatar_size), - Masking = true, - CornerRadius = avatar_size * 0.25f, + RelativeSizeAxes = Axes.X, + Height = 250, }, - new OsuContextMenuContainer + new FillFlowContainer { - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X, - Child = new Container + Direction = FillDirection.Horizontal, + Margin = new MarginPadding { - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X, - Padding = new MarginPadding { Left = 10 }, - Children = new Drawable[] + Left = UserProfileOverlay.CONTENT_X_MARGIN, + Vertical = 10 + }, + Height = avatar_size, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + avatar = new UpdateableAvatar(isInteractive: false, showGuestOnNull: false) { - new FillFlowContainer + Size = new Vector2(avatar_size), + Masking = true, + CornerRadius = avatar_size * 0.25f, + }, + new OsuContextMenuContainer + { + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Child = new Container { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Padding = new MarginPadding { Left = 10 }, Children = new Drawable[] { new FillFlowContainer { AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(5), + Direction = FillDirection.Vertical, Children = new Drawable[] { - usernameText = new OsuSpriteText + new FillFlowContainer { - Font = OsuFont.GetFont(size: 24, weight: FontWeight.Regular) + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Children = new Drawable[] + { + usernameText = new OsuSpriteText + { + Font = OsuFont.GetFont(size: 24, weight: FontWeight.Regular) + }, + openUserExternally = new ExternalLinkButton + { + Margin = new MarginPadding { Left = 5 }, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, + } }, - openUserExternally = new ExternalLinkButton + titleText = new OsuSpriteText { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(size: 18, weight: FontWeight.Regular) }, groupBadgeFlow = new GroupBadgeFlow { @@ -105,54 +129,50 @@ namespace osu.Game.Overlays.Profile.Header } } }, - titleText = new OsuSpriteText - { - Font = OsuFont.GetFont(size: 18, weight: FontWeight.Regular) - }, - } - }, - new FillFlowContainer - { - Origin = Anchor.BottomLeft, - Anchor = Anchor.BottomLeft, - Direction = FillDirection.Vertical, - AutoSizeAxes = Axes.Both, - Children = new Drawable[] - { - supporterTag = new SupporterIcon - { - Height = 20, - Margin = new MarginPadding { Top = 5 } - }, - new Box - { - RelativeSizeAxes = Axes.X, - Height = 1.5f, - Margin = new MarginPadding { Top = 10 }, - Colour = colourProvider.Light1, - }, new FillFlowContainer { + Origin = Anchor.BottomLeft, + Anchor = Anchor.BottomLeft, + Direction = FillDirection.Vertical, AutoSizeAxes = Axes.Both, - Margin = new MarginPadding { Top = 5 }, - Direction = FillDirection.Horizontal, Children = new Drawable[] { - userFlag = new UpdateableFlag + supporterTag = new SupporterIcon { - Size = new Vector2(28, 20), - ShowPlaceholderOnUnknown = false, + Height = 20, + Margin = new MarginPadding { Top = 5 } }, - userCountryText = new OsuSpriteText + new Box { - Font = OsuFont.GetFont(size: 17.5f, weight: FontWeight.Regular), - Margin = new MarginPadding { Left = 10 }, - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, + RelativeSizeAxes = Axes.X, + Height = 1.5f, + Margin = new MarginPadding { Top = 10 }, Colour = colourProvider.Light1, - } + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Margin = new MarginPadding { Top = 5 }, + Direction = FillDirection.Horizontal, + Children = new Drawable[] + { + userFlag = new UpdateableFlag + { + Size = new Vector2(28, 20), + ShowPlaceholderOnUnknown = false, + }, + userCountryText = new OsuSpriteText + { + Font = OsuFont.GetFont(size: 17.5f, weight: FontWeight.Regular), + Margin = new MarginPadding { Left = 10 }, + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + Colour = colourProvider.Light1, + } + } + }, } - }, + } } } } @@ -169,6 +189,7 @@ namespace osu.Game.Overlays.Profile.Header { var user = data?.User; + cover.User = user; avatar.User = user; usernameText.Text = user?.Username ?? string.Empty; openUserExternally.Link = $@"{api.WebsiteRootUrl}/users/{user?.Id ?? 0}"; @@ -179,5 +200,15 @@ namespace osu.Game.Overlays.Profile.Header titleText.Colour = Color4Extensions.FromHex(user?.Colour ?? "fff"); groupBadgeFlow.User.Value = user; } + + private partial class ProfileCoverBackground : UserCoverBackground + { + protected override double LoadDelay => 0; + + public ProfileCoverBackground() + { + Masking = true; + } + } } } diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index c559a1c102..67b723b7e6 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -3,23 +3,17 @@ using System.Diagnostics; using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; using osu.Framework.Localisation; using osu.Game.Overlays.Profile.Header; using osu.Game.Overlays.Profile.Header.Components; using osu.Game.Resources.Localisation.Web; -using osu.Game.Users; namespace osu.Game.Overlays.Profile { public partial class ProfileHeader : TabControlOverlayHeader { - private UserCoverBackground coverContainer = null!; - public Bindable User = new Bindable(); private CentreHeaderContainer centreHeaderContainer; @@ -29,8 +23,6 @@ namespace osu.Game.Overlays.Profile { ContentSidePadding = UserProfileOverlay.CONTENT_X_MARGIN; - User.ValueChanged += e => updateDisplay(e.NewValue); - TabControl.AddItem(LayoutStrings.HeaderUsersShow); // todo: pending implementation. @@ -41,25 +33,7 @@ namespace osu.Game.Overlays.Profile Debug.Assert(detailHeaderContainer != null); } - protected override Drawable CreateBackground() => - new Container - { - RelativeSizeAxes = Axes.X, - Height = 150, - Masking = true, - Children = new Drawable[] - { - coverContainer = new ProfileCoverBackground - { - RelativeSizeAxes = Axes.Both, - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientVertical(Color4Extensions.FromHex("222").Opacity(0.8f), Color4Extensions.FromHex("222").Opacity(0.2f)) - }, - } - }; + protected override Drawable CreateBackground() => Empty(); protected override Drawable CreateContent() => new FillFlowContainer { @@ -103,8 +77,6 @@ namespace osu.Game.Overlays.Profile User = { BindTarget = User } }; - private void updateDisplay(UserProfileData? user) => coverContainer.User = user?.User; - private partial class ProfileHeaderTitle : OverlayTitle { public ProfileHeaderTitle() @@ -113,10 +85,5 @@ namespace osu.Game.Overlays.Profile IconTexture = "Icons/Hexacons/profile"; } } - - private partial class ProfileCoverBackground : UserCoverBackground - { - protected override double LoadDelay => 0; - } } } From ef7812412b5eadf301de7aa2d7e090f450d76d65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 31 Dec 2022 19:58:58 +0100 Subject: [PATCH 162/430] Update top header container appearance --- .../Online/TestSceneUserProfileOverlay.cs | 5 +- .../Profile/Header/TopHeaderContainer.cs | 114 ++++++++---------- 2 files changed, 54 insertions(+), 65 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs index fc8c2c0b6e..9aaa616c04 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs @@ -82,7 +82,7 @@ namespace osu.Game.Tests.Visual.Online { Username = @"Somebody", Id = 1, - CountryCode = CountryCode.Unknown, + CountryCode = CountryCode.JP, CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c1.jpg", JoinDate = DateTimeOffset.Now.AddDays(-1), LastVisit = DateTimeOffset.Now, @@ -143,7 +143,8 @@ namespace osu.Game.Tests.Visual.Online { Available = 10, Total = 50 - } + }, + SupportLevel = 2, }; } } diff --git a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs index 270be7cdf4..a71db23989 100644 --- a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs @@ -7,6 +7,7 @@ using osu.Framework.Extensions; 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.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -22,7 +23,7 @@ namespace osu.Game.Overlays.Profile.Header { public partial class TopHeaderContainer : CompositeDrawable { - private const float avatar_size = 110; + private const float avatar_size = 120; public readonly Bindable User = new Bindable(); @@ -67,60 +68,66 @@ namespace osu.Game.Overlays.Profile.Header new FillFlowContainer { Direction = FillDirection.Horizontal, - Margin = new MarginPadding + Padding = new MarginPadding { Left = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 }, - Height = avatar_size, + Spacing = new Vector2(20, 0), + Height = 85, RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, Children = new Drawable[] { avatar = new UpdateableAvatar(isInteractive: false, showGuestOnNull: false) { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, Size = new Vector2(avatar_size), Masking = true, CornerRadius = avatar_size * 0.25f, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Offset = new Vector2(0, 1), + Radius = 3, + Colour = Colour4.Black.Opacity(0.25f), + } }, new OsuContextMenuContainer { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, RelativeSizeAxes = Axes.Y, AutoSizeAxes = Axes.X, - Child = new Container + Child = new FillFlowContainer { - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X, - Padding = new MarginPadding { Left = 10 }, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, Children = new Drawable[] { new FillFlowContainer { AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5, 0), Children = new Drawable[] { - new FillFlowContainer + usernameText = new OsuSpriteText { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Children = new Drawable[] - { - usernameText = new OsuSpriteText - { - Font = OsuFont.GetFont(size: 24, weight: FontWeight.Regular) - }, - openUserExternally = new ExternalLinkButton - { - Margin = new MarginPadding { Left = 5 }, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - }, - } + Font = OsuFont.GetFont(size: 24, weight: FontWeight.Regular) }, - titleText = new OsuSpriteText + supporterTag = new SupporterIcon { - Font = OsuFont.GetFont(size: 18, weight: FontWeight.Regular) + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Height = 15, + }, + openUserExternally = new ExternalLinkButton + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, }, groupBadgeFlow = new GroupBadgeFlow { @@ -129,52 +136,33 @@ namespace osu.Game.Overlays.Profile.Header } } }, + titleText = new OsuSpriteText + { + Font = OsuFont.GetFont(size: 16, weight: FontWeight.Regular), + Margin = new MarginPadding { Bottom = 5 } + }, new FillFlowContainer { - Origin = Anchor.BottomLeft, - Anchor = Anchor.BottomLeft, - Direction = FillDirection.Vertical, AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, Children = new Drawable[] { - supporterTag = new SupporterIcon + userFlag = new UpdateableFlag { - Height = 20, - Margin = new MarginPadding { Top = 5 } + Size = new Vector2(28, 20), + ShowPlaceholderOnUnknown = false, }, - new Box + userCountryText = new OsuSpriteText { - RelativeSizeAxes = Axes.X, - Height = 1.5f, - Margin = new MarginPadding { Top = 10 }, - Colour = colourProvider.Light1, - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Margin = new MarginPadding { Top = 5 }, - Direction = FillDirection.Horizontal, - Children = new Drawable[] - { - userFlag = new UpdateableFlag - { - Size = new Vector2(28, 20), - ShowPlaceholderOnUnknown = false, - }, - userCountryText = new OsuSpriteText - { - Font = OsuFont.GetFont(size: 17.5f, weight: FontWeight.Regular), - Margin = new MarginPadding { Left = 10 }, - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, - Colour = colourProvider.Light1, - } - } - }, + Font = OsuFont.GetFont(size: 14f, weight: FontWeight.Regular), + Margin = new MarginPadding { Left = 5 }, + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + } } - } + }, } - } + }, } } } From e74176e5bd49fdf2462bf93fbf81225c5b7bb5e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 31 Dec 2022 20:09:49 +0100 Subject: [PATCH 163/430] Add cover toggle button --- ...dDetailsButton.cs => ToggleCoverButton.cs} | 21 +- .../Profile/Header/TopHeaderContainer.cs | 198 ++++++++++-------- 2 files changed, 117 insertions(+), 102 deletions(-) rename osu.Game/Overlays/Profile/Header/Components/{ExpandDetailsButton.cs => ToggleCoverButton.cs} (68%) diff --git a/osu.Game/Overlays/Profile/Header/Components/ExpandDetailsButton.cs b/osu.Game/Overlays/Profile/Header/Components/ToggleCoverButton.cs similarity index 68% rename from osu.Game/Overlays/Profile/Header/Components/ExpandDetailsButton.cs rename to osu.Game/Overlays/Profile/Header/Components/ToggleCoverButton.cs index e7a83c95d8..9ae529f3ae 100644 --- a/osu.Game/Overlays/Profile/Header/Components/ExpandDetailsButton.cs +++ b/osu.Game/Overlays/Profile/Header/Components/ToggleCoverButton.cs @@ -5,7 +5,6 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; @@ -15,11 +14,11 @@ using osuTK; namespace osu.Game.Overlays.Profile.Header.Components { - public partial class ExpandDetailsButton : ProfileHeaderButton + public partial class ToggleCoverButton : ProfileHeaderButton { - public readonly BindableBool DetailsVisible = new BindableBool(); + public readonly BindableBool CoverVisible = new BindableBool(); - public override LocalisableString TooltipText => DetailsVisible.Value ? CommonStrings.ButtonsCollapse : CommonStrings.ButtonsExpand; + public override LocalisableString TooltipText => CoverVisible.Value ? UsersStrings.ShowCoverTo0 : UsersStrings.ShowCoverTo1; private SpriteIcon icon = null!; private Sample? sampleOpen; @@ -27,12 +26,12 @@ namespace osu.Game.Overlays.Profile.Header.Components protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverClickSounds(); - public ExpandDetailsButton() + public ToggleCoverButton() { Action = () => { - DetailsVisible.Toggle(); - (DetailsVisible.Value ? sampleOpen : sampleClose)?.Play(); + CoverVisible.Toggle(); + (CoverVisible.Value ? sampleOpen : sampleClose)?.Play(); }; } @@ -40,19 +39,21 @@ namespace osu.Game.Overlays.Profile.Header.Components private void load(OverlayColourProvider colourProvider, AudioManager audio) { IdleColour = colourProvider.Background2; - HoverColour = colourProvider.Background2.Lighten(0.2f); + HoverColour = colourProvider.Background1; sampleOpen = audio.Samples.Get(@"UI/dropdown-open"); sampleClose = audio.Samples.Get(@"UI/dropdown-close"); + AutoSizeAxes = Axes.None; + Size = new Vector2(30); Child = icon = new SpriteIcon { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Size = new Vector2(20, 12) + Size = new Vector2(10.5f, 12) }; - DetailsVisible.BindValueChanged(visible => updateState(visible.NewValue), true); + CoverVisible.BindValueChanged(visible => updateState(visible.NewValue), true); } private void updateState(bool detailsVisible) => icon.Icon = detailsVisible ? FontAwesome.Solid.ChevronUp : FontAwesome.Solid.ChevronDown; diff --git a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs index a71db23989..0204800326 100644 --- a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs @@ -65,108 +65,122 @@ namespace osu.Game.Overlays.Profile.Header RelativeSizeAxes = Axes.X, Height = 250, }, - new FillFlowContainer + new Container { - Direction = FillDirection.Horizontal, - Padding = new MarginPadding - { - Left = UserProfileOverlay.CONTENT_X_MARGIN, - Vertical = 10 - }, - Spacing = new Vector2(20, 0), - Height = 85, RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, Children = new Drawable[] { - avatar = new UpdateableAvatar(isInteractive: false, showGuestOnNull: false) + new FillFlowContainer { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Size = new Vector2(avatar_size), - Masking = true, - CornerRadius = avatar_size * 0.25f, - EdgeEffect = new EdgeEffectParameters + Direction = FillDirection.Horizontal, + Padding = new MarginPadding { - Type = EdgeEffectType.Shadow, - Offset = new Vector2(0, 1), - Radius = 3, - Colour = Colour4.Black.Opacity(0.25f), + Left = UserProfileOverlay.CONTENT_X_MARGIN, + Vertical = 10 + }, + Spacing = new Vector2(20, 0), + Height = 85, + RelativeSizeAxes = Axes.X, + Children = new Drawable[] + { + avatar = new UpdateableAvatar(isInteractive: false, showGuestOnNull: false) + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Size = new Vector2(avatar_size), + Masking = true, + CornerRadius = avatar_size * 0.25f, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Offset = new Vector2(0, 1), + Radius = 3, + Colour = Colour4.Black.Opacity(0.25f), + } + }, + new OsuContextMenuContainer + { + 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[] + { + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5, 0), + Children = new Drawable[] + { + 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[] + { + 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, + } + } + }, + } + }, + }, } }, - new OsuContextMenuContainer + new ToggleCoverButton { - 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[] - { - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(5, 0), - Children = new Drawable[] - { - 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[] - { - 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.CentreRight, + Origin = Anchor.CentreRight, + Margin = new MarginPadding { Right = 10 } } - } - } - } + }, + }, + }, }, }; From 33e91cf51227294bec0ccf74904ef18813aafd2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 31 Dec 2022 20:28:28 +0100 Subject: [PATCH 164/430] Implement cover toggling --- .../Header/Components/ToggleCoverButton.cs | 2 +- .../Profile/Header/TopHeaderContainer.cs | 31 ++++++++++++++----- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/Components/ToggleCoverButton.cs b/osu.Game/Overlays/Profile/Header/Components/ToggleCoverButton.cs index 9ae529f3ae..ef13f089c3 100644 --- a/osu.Game/Overlays/Profile/Header/Components/ToggleCoverButton.cs +++ b/osu.Game/Overlays/Profile/Header/Components/ToggleCoverButton.cs @@ -16,7 +16,7 @@ namespace osu.Game.Overlays.Profile.Header.Components { public partial class ToggleCoverButton : ProfileHeaderButton { - public readonly BindableBool CoverVisible = new BindableBool(); + public readonly BindableBool CoverVisible = new BindableBool(true); public override LocalisableString TooltipText => CoverVisible.Value ? UsersStrings.ShowCoverTo0 : UsersStrings.ShowCoverTo1; diff --git a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs index 0204800326..ce0c56b52b 100644 --- a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs @@ -23,7 +23,8 @@ namespace osu.Game.Overlays.Profile.Header { public partial class TopHeaderContainer : CompositeDrawable { - private const float avatar_size = 120; + private const float content_height = 65; + private const float vertical_padding = 10; public readonly Bindable User = new Bindable(); @@ -39,6 +40,7 @@ namespace osu.Game.Overlays.Profile.Header private UpdateableFlag userFlag = null!; private OsuSpriteText userCountryText = null!; private GroupBadgeFlow groupBadgeFlow = null!; + private ToggleCoverButton coverToggle = null!; [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) @@ -63,7 +65,6 @@ namespace osu.Game.Overlays.Profile.Header cover = new ProfileCoverBackground { RelativeSizeAxes = Axes.X, - Height = 250, }, new Container { @@ -77,10 +78,10 @@ namespace osu.Game.Overlays.Profile.Header Padding = new MarginPadding { Left = UserProfileOverlay.CONTENT_X_MARGIN, - Vertical = 10 + Vertical = vertical_padding }, Spacing = new Vector2(20, 0), - Height = 85, + Height = content_height + 2 * vertical_padding, RelativeSizeAxes = Axes.X, Children = new Drawable[] { @@ -88,9 +89,7 @@ namespace osu.Game.Overlays.Profile.Header { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, - Size = new Vector2(avatar_size), Masking = true, - CornerRadius = avatar_size * 0.25f, EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Shadow, @@ -172,7 +171,7 @@ namespace osu.Game.Overlays.Profile.Header }, } }, - new ToggleCoverButton + coverToggle = new ToggleCoverButton { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, @@ -183,8 +182,15 @@ namespace osu.Game.Overlays.Profile.Header }, }, }; + } - User.BindValueChanged(user => updateUser(user.NewValue)); + protected override void LoadComplete() + { + base.LoadComplete(); + + User.BindValueChanged(user => updateUser(user.NewValue), true); + coverToggle.CoverVisible.BindValueChanged(_ => updateCoverState(), true); + FinishTransforms(true); } private void updateUser(UserProfileData? data) @@ -203,6 +209,15 @@ namespace osu.Game.Overlays.Profile.Header groupBadgeFlow.User.Value = user; } + private void updateCoverState() + { + const float transition_duration = 250; + + cover.ResizeHeightTo(coverToggle.CoverVisible.Value ? 250 : 0, transition_duration, Easing.OutQuint); + avatar.ResizeTo(new Vector2(coverToggle.CoverVisible.Value ? 120 : content_height), transition_duration, Easing.OutQuint); + avatar.TransformTo(nameof(avatar.CornerRadius), coverToggle.CoverVisible.Value ? 40f : 20f, transition_duration, Easing.OutQuint); + } + private partial class ProfileCoverBackground : UserCoverBackground { protected override double LoadDelay => 0; From f2df36e6a556be58a73df652d778aea35b0e780b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 24 Jan 2023 23:30:07 +0100 Subject: [PATCH 165/430] Persist cover visibility to user settings Follows web precedent, wherein the setting is saved to local storage. --- .../Online/TestSceneUserProfileHeader.cs | 20 +++++++++++++++++++ osu.Game/Configuration/OsuConfigManager.cs | 3 +++ .../Header/Components/ToggleCoverButton.cs | 10 +++++----- .../Profile/Header/TopHeaderContainer.cs | 18 +++++++++++------ 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs index 513c473830..640e895b6c 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs @@ -6,6 +6,7 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Testing; +using osu.Game.Configuration; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.Profile; @@ -19,6 +20,9 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); + [Resolved] + private OsuConfigManager configManager { get; set; } = null!; + private ProfileHeader header = null!; [SetUpSteps] @@ -33,6 +37,22 @@ namespace osu.Game.Tests.Visual.Online AddStep("Show example user", () => header.User.Value = new UserProfileData(TestSceneUserProfileOverlay.TEST_USER, new OsuRuleset().RulesetInfo)); } + [Test] + public void TestProfileCoverExpanded() + { + AddStep("Set cover to expanded", () => configManager.SetValue(OsuSetting.ProfileCoverExpanded, true)); + AddStep("Show example user", () => header.User.Value = new UserProfileData(TestSceneUserProfileOverlay.TEST_USER, new OsuRuleset().RulesetInfo)); + AddUntilStep("Cover is expanded", () => header.ChildrenOfType().Single().Height, () => Is.GreaterThan(0)); + } + + [Test] + public void TestProfileCoverCollapsed() + { + AddStep("Set cover to collapsed", () => configManager.SetValue(OsuSetting.ProfileCoverExpanded, false)); + AddStep("Show example user", () => header.User.Value = new UserProfileData(TestSceneUserProfileOverlay.TEST_USER, new OsuRuleset().RulesetInfo)); + AddUntilStep("Cover is collapsed", () => header.ChildrenOfType().Single().Height, () => Is.EqualTo(0)); + } + [Test] public void TestOnlineState() { diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 6cbb677a64..507d5e611c 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -58,6 +58,8 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.BeatmapListingCardSize, BeatmapCardSize.Normal); + SetDefault(OsuSetting.ProfileCoverExpanded, true); + SetDefault(OsuSetting.ToolbarClockDisplayMode, ToolbarClockDisplayMode.Full); // Online settings @@ -375,5 +377,6 @@ namespace osu.Game.Configuration LastProcessedMetadataId, SafeAreaConsiderations, ComboColourNormalisationAmount, + ProfileCoverExpanded, } } diff --git a/osu.Game/Overlays/Profile/Header/Components/ToggleCoverButton.cs b/osu.Game/Overlays/Profile/Header/Components/ToggleCoverButton.cs index ef13f089c3..9171d5de7d 100644 --- a/osu.Game/Overlays/Profile/Header/Components/ToggleCoverButton.cs +++ b/osu.Game/Overlays/Profile/Header/Components/ToggleCoverButton.cs @@ -16,9 +16,9 @@ namespace osu.Game.Overlays.Profile.Header.Components { public partial class ToggleCoverButton : ProfileHeaderButton { - public readonly BindableBool CoverVisible = new BindableBool(true); + public readonly BindableBool CoverExpanded = new BindableBool(true); - public override LocalisableString TooltipText => CoverVisible.Value ? UsersStrings.ShowCoverTo0 : UsersStrings.ShowCoverTo1; + public override LocalisableString TooltipText => CoverExpanded.Value ? UsersStrings.ShowCoverTo0 : UsersStrings.ShowCoverTo1; private SpriteIcon icon = null!; private Sample? sampleOpen; @@ -30,8 +30,8 @@ namespace osu.Game.Overlays.Profile.Header.Components { Action = () => { - CoverVisible.Toggle(); - (CoverVisible.Value ? sampleOpen : sampleClose)?.Play(); + CoverExpanded.Toggle(); + (CoverExpanded.Value ? sampleOpen : sampleClose)?.Play(); }; } @@ -53,7 +53,7 @@ namespace osu.Game.Overlays.Profile.Header.Components Size = new Vector2(10.5f, 12) }; - CoverVisible.BindValueChanged(visible => updateState(visible.NewValue), true); + CoverExpanded.BindValueChanged(visible => updateState(visible.NewValue), true); } private void updateState(bool detailsVisible) => icon.Icon = detailsVisible ? FontAwesome.Solid.ChevronUp : FontAwesome.Solid.ChevronDown; diff --git a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs index ce0c56b52b..389f2301c4 100644 --- a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; +using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Cursor; @@ -42,12 +43,16 @@ namespace osu.Game.Overlays.Profile.Header private GroupBadgeFlow groupBadgeFlow = null!; private ToggleCoverButton coverToggle = null!; + private Bindable coverExpanded = null!; + [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) + private void load(OverlayColourProvider colourProvider, OsuConfigManager configManager) { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; + coverExpanded = configManager.GetBindable(OsuSetting.ProfileCoverExpanded); + InternalChildren = new Drawable[] { new Box @@ -175,7 +180,8 @@ namespace osu.Game.Overlays.Profile.Header { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, - Margin = new MarginPadding { Right = 10 } + Margin = new MarginPadding { Right = 10 }, + CoverExpanded = { BindTarget = coverExpanded } } }, }, @@ -189,7 +195,7 @@ namespace osu.Game.Overlays.Profile.Header base.LoadComplete(); User.BindValueChanged(user => updateUser(user.NewValue), true); - coverToggle.CoverVisible.BindValueChanged(_ => updateCoverState(), true); + coverExpanded.BindValueChanged(_ => updateCoverState(), true); FinishTransforms(true); } @@ -213,9 +219,9 @@ namespace osu.Game.Overlays.Profile.Header { const float transition_duration = 250; - cover.ResizeHeightTo(coverToggle.CoverVisible.Value ? 250 : 0, transition_duration, Easing.OutQuint); - avatar.ResizeTo(new Vector2(coverToggle.CoverVisible.Value ? 120 : content_height), transition_duration, Easing.OutQuint); - avatar.TransformTo(nameof(avatar.CornerRadius), coverToggle.CoverVisible.Value ? 40f : 20f, transition_duration, Easing.OutQuint); + cover.ResizeHeightTo(coverToggle.CoverExpanded.Value ? 250 : 0, transition_duration, Easing.OutQuint); + avatar.ResizeTo(new Vector2(coverToggle.CoverExpanded.Value ? 120 : content_height), transition_duration, Easing.OutQuint); + avatar.TransformTo(nameof(avatar.CornerRadius), coverToggle.CoverExpanded.Value ? 40f : 20f, transition_duration, Easing.OutQuint); } private partial class ProfileCoverBackground : UserCoverBackground From 4d7cd59df39faa42f462f20e39ea4db45ebd5af2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 24 Jan 2023 23:58:39 +0100 Subject: [PATCH 166/430] Fix `TestAbsoluteImage()` no longer actually testing absolute image URL --- osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs index ab9fae5d2c..ba9830181e 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs @@ -123,7 +123,7 @@ needs_cleanup: true AddStep("Add absolute image", () => { markdownContainer.CurrentPath = "https://dev.ppy.sh"; - markdownContainer.Text = "![intro](wiki/images/Client/Interface/img/intro-screen.jpg)"; + markdownContainer.Text = "![intro](/wiki/images/Client/Interface/img/intro-screen.jpg)"; }); } From a3bb6d1fab3a658d1b3566fa602db763c741814f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 25 Jan 2023 00:00:16 +0100 Subject: [PATCH 167/430] Revert a few more relative to absolute changes Because not sure why they were changed in the first place. --- .../Online/TestSceneWikiMarkdownContainer.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs index ba9830181e..0aa0295f7d 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs @@ -157,7 +157,7 @@ Line after image"; AddStep("Add inline image", () => { markdownContainer.CurrentPath = "https://dev.ppy.sh"; - markdownContainer.Text = "![osu! mode icon](wiki/shared/mode/osu.png) osu!"; + markdownContainer.Text = "![osu! mode icon](/wiki/shared/mode/osu.png) osu!"; }); } @@ -170,12 +170,12 @@ Line after image"; markdownContainer.Text = @" | Image | Name | Effect | | :-: | :-: | :-- | -| ![](wiki/images/shared/judgement/osu!/hit300.png ""300"") | 300 | A possible score when tapping a hit circle precisely on time, completing a Slider and keeping the cursor over every tick, or completing a Spinner with the Spinner Metre full. A score of 300 appears in an blue score by default. Scoring nothing except 300s in a beatmap will award the player with the SS or SSH grade. | -| ![](wiki/images/shared/judgement/osu!/hit300g.png ""Geki"") | (激) Geki | A term from Ouendan, called Elite Beat! in EBA. Appears when playing the last element in a combo in which the player has scored only 300s. Getting a Geki will give a sizable boost to the Life Bar. By default, it is blue. | -| ![](wiki/images/shared/judgement/osu!/hit100.png ""100"") | 100 | A possible score one can get when tapping a Hit Object slightly late or early, completing a Slider and missing a number of ticks, or completing a Spinner with the Spinner Meter almost full. A score of 100 appears in a green score by default. When very skilled players test a beatmap and they get a lot of 100s, this may mean that the beatmap does not have correct timing. | -| ![](wiki/images/shared/judgement/osu!/hit300k.png ""300 Katu"") ![](/wiki/Skinning/Interface/img/hit100k.png ""100 Katu"") | (喝) Katu or Katsu | A term from Ouendan, called Beat! in EBA. Appears when playing the last element in a combo in which the player has scored at least one 100, but no 50s or misses. Getting a Katu will give a small boost to the Life Bar. By default, it is coloured green or blue depending on whether the Katu itself is a 100 or a 300. | -| ![](wiki/images/shared/judgement/osu!/hit50.png ""50"") | 50 | A possible score one can get when tapping a hit circle rather early or late but not early or late enough to cause a miss, completing a Slider and missing a lot of ticks, or completing a Spinner with the Spinner Metre close to full. A score of 50 appears in a orange score by default. Scoring a 50 in a combo will prevent the appearance of a Katu or a Geki at the combo's end. | -| ![](wiki/images/shared/judgement/osu!/hit0.png ""Miss"") | Miss | A possible score one can get when not tapping a hit circle or too early (based on OD and AR, it may *shake* instead), not tapping or holding the Slider at least once, or completing a Spinner with low Spinner Metre fill. Scoring a Miss will reset the current combo to 0 and will prevent the appearance of a Katu or a Geki at the combo's end. | +| ![](/wiki/images/shared/judgement/osu!/hit300.png ""300"") | 300 | A possible score when tapping a hit circle precisely on time, completing a Slider and keeping the cursor over every tick, or completing a Spinner with the Spinner Metre full. A score of 300 appears in an blue score by default. Scoring nothing except 300s in a beatmap will award the player with the SS or SSH grade. | +| ![](/wiki/images/shared/judgement/osu!/hit300g.png ""Geki"") | (激) Geki | A term from Ouendan, called Elite Beat! in EBA. Appears when playing the last element in a combo in which the player has scored only 300s. Getting a Geki will give a sizable boost to the Life Bar. By default, it is blue. | +| ![](/wiki/images/shared/judgement/osu!/hit100.png ""100"") | 100 | A possible score one can get when tapping a Hit Object slightly late or early, completing a Slider and missing a number of ticks, or completing a Spinner with the Spinner Meter almost full. A score of 100 appears in a green score by default. When very skilled players test a beatmap and they get a lot of 100s, this may mean that the beatmap does not have correct timing. | +| ![](/wiki/images/shared/judgement/osu!/hit300k.png ""300 Katu"") ![](/wiki/Skinning/Interface/img/hit100k.png ""100 Katu"") | (喝) Katu or Katsu | A term from Ouendan, called Beat! in EBA. Appears when playing the last element in a combo in which the player has scored at least one 100, but no 50s or misses. Getting a Katu will give a small boost to the Life Bar. By default, it is coloured green or blue depending on whether the Katu itself is a 100 or a 300. | +| ![](/wiki/images/shared/judgement/osu!/hit50.png ""50"") | 50 | A possible score one can get when tapping a hit circle rather early or late but not early or late enough to cause a miss, completing a Slider and missing a lot of ticks, or completing a Spinner with the Spinner Metre close to full. A score of 50 appears in a orange score by default. Scoring a 50 in a combo will prevent the appearance of a Katu or a Geki at the combo's end. | +| ![](/wiki/images/shared/judgement/osu!/hit0.png ""Miss"") | Miss | A possible score one can get when not tapping a hit circle or too early (based on OD and AR, it may *shake* instead), not tapping or holding the Slider at least once, or completing a Spinner with low Spinner Metre fill. Scoring a Miss will reset the current combo to 0 and will prevent the appearance of a Katu or a Geki at the combo's end. | "; }); } From 4d4dfd9e8b7b263734edec6cb692e9174df8d7bc Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 25 Jan 2023 02:15:01 +0300 Subject: [PATCH 168/430] Fix iOS workflow still targeting old Xcode version --- .github/workflows/ci.yml | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 213c5082ab..5c11f91994 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -121,21 +121,12 @@ jobs: build-only-ios: name: Build only (iOS) - # change to macos-latest once GitHub finishes migrating all repositories to macOS 12. - runs-on: macos-12 + runs-on: macos-latest timeout-minutes: 60 steps: - name: Checkout uses: actions/checkout@v2 - # see https://github.com/actions/runner-images/issues/6771#issuecomment-1354713617 - # remove once all workflow VMs use Xcode 14.1 - - name: Set Xcode Version - shell: bash - run: | - sudo xcode-select -s "/Applications/Xcode_14.1.app" - echo "MD_APPLE_SDK_ROOT=/Applications/Xcode_14.1.app" >> $GITHUB_ENV - - name: Install .NET 6.0.x uses: actions/setup-dotnet@v1 with: From d8365f4fca4bfc0c52f261eaf79e67eafa7a8eb5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Jan 2023 11:47:15 +0900 Subject: [PATCH 169/430] Reverse order of application to match `DrawableHitObject` --- osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs index a62efa96bf..23c18d9207 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs @@ -122,10 +122,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon // Schedule the change to avoid transforms piling up. Scheduler.AddOnce(() => { - updateStateTransforms(drawableObject, drawableObject.State.Value); - ApplyTransformsAt(double.MinValue, true); ClearTransformsAfter(double.MinValue, true); + + updateStateTransforms(drawableObject, drawableObject.State.Value); }); }, true); From 5f037ac1e95493f87847a34ff4f08d260abb95da Mon Sep 17 00:00:00 2001 From: itsMapleLeaf <19603573+itsMapleLeaf@users.noreply.github.com> Date: Tue, 24 Jan 2023 22:24:21 -0600 Subject: [PATCH 170/430] comment not useful --- .../Skinning/Argon/ArgonHoldNoteTailPiece.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs index 02325904c4..a14abf7011 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs @@ -23,8 +23,6 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon public ArgonHoldNoteTailPiece() { RelativeSizeAxes = Axes.X; - - // multiply by two so that the hold body extends up to the height of the note head accent Height = ArgonNotePiece.NOTE_HEIGHT * 2; CornerRadius = ArgonNotePiece.CORNER_RADIUS; From 132417b4e4e9880e3336783743c120afe7e18a0c Mon Sep 17 00:00:00 2001 From: itsMapleLeaf <19603573+itsMapleLeaf@users.noreply.github.com> Date: Tue, 24 Jan 2023 22:36:13 -0600 Subject: [PATCH 171/430] fix braces --- .../Skinning/Argon/ArgonHoldNoteTailPiece.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs index a14abf7011..b2cccfac26 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs @@ -30,12 +30,14 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon InternalChildren = new Drawable[] { - shadeContainer = new Container { + shadeContainer = new Container + { RelativeSizeAxes = Axes.Both, Height = 0.5f, CornerRadius = ArgonNotePiece.CORNER_RADIUS, Masking = true, - Children = new Drawable[] { + Children = new Drawable[] + { new Box { RelativeSizeAxes = Axes.Both, @@ -44,7 +46,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon }, }, }, - hitLine = new Circle { + hitLine = new Circle + { RelativeSizeAxes = Axes.X, Height = ArgonNotePiece.CORNER_RADIUS * 2, }, From 739ec8d81d7c680aca106e7b49a4d7d43de67ca2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Jan 2023 14:04:30 +0900 Subject: [PATCH 172/430] Add argument hint for nondescript `bool` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/Beatmaps/BeatmapManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index fc6d4081e7..89fe498f89 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -186,7 +186,7 @@ namespace osu.Game.Beatmaps targetBeatmapSet.Beatmaps.Add(newBeatmap.BeatmapInfo); newBeatmap.BeatmapInfo.BeatmapSet = targetBeatmapSet; - save(newBeatmap.BeatmapInfo, newBeatmap, beatmapSkin, false); + save(newBeatmap.BeatmapInfo, newBeatmap, beatmapSkin, transferCollections: false); workingBeatmapCache.Invalidate(targetBeatmapSet); return GetWorkingBeatmap(newBeatmap.BeatmapInfo); From 741ca968531f33dbd2f099a3d32d00d23ac4cb39 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Jan 2023 14:09:13 +0900 Subject: [PATCH 173/430] Make `transferCollections` argument to private method explicitly required --- osu.Game/Beatmaps/BeatmapManager.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 89fe498f89..f39523cedf 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -286,10 +286,8 @@ namespace osu.Game.Beatmaps /// The to save the content against. The file referenced by will be replaced. /// The content to write. /// The beatmap content to write, null if to be omitted. - public virtual void Save(BeatmapInfo beatmapInfo, IBeatmap beatmapContent, ISkin? beatmapSkin = null) - { - save(beatmapInfo, beatmapContent, beatmapSkin); - } + public virtual void Save(BeatmapInfo beatmapInfo, IBeatmap beatmapContent, ISkin? beatmapSkin = null) => + save(beatmapInfo, beatmapContent, beatmapSkin, transferCollections: true); public void DeleteAllVideos() { @@ -399,7 +397,7 @@ namespace osu.Game.Beatmaps setInfo.Status = BeatmapOnlineStatus.LocallyModified; } - private void save(BeatmapInfo beatmapInfo, IBeatmap beatmapContent, ISkin? beatmapSkin, bool transferCollections = true) + private void save(BeatmapInfo beatmapInfo, IBeatmap beatmapContent, ISkin? beatmapSkin, bool transferCollections) { var setInfo = beatmapInfo.BeatmapSet; Debug.Assert(setInfo != null); From 392ff2ffea6273063402d97580df9123b4874dd4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Jan 2023 14:11:02 +0900 Subject: [PATCH 174/430] Reword comment regarding hash transfer to make more sense --- osu.Game/Beatmaps/BeatmapManager.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index f39523cedf..ad56bbbc3a 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -280,9 +280,11 @@ namespace osu.Game.Beatmaps public IWorkingBeatmap DefaultBeatmap => workingBeatmapCache.DefaultBeatmap; /// - /// Saves an existing file against a given , also transferring the beatmap - /// hashes in any collections referencing it. + /// Saves an existing file against a given . /// + /// + /// This method will also update any user beatmap collection hash references to the new post-saved hash. + /// /// The to save the content against. The file referenced by will be replaced. /// The content to write. /// The beatmap content to write, null if to be omitted. From 3e91dd2a16094a84f6fdbeeadfbafe06a14999db Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Jan 2023 14:27:44 +0900 Subject: [PATCH 175/430] Update spacing along with expanded state --- .../Overlays/Profile/Header/TopHeaderContainer.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs index 389f2301c4..57197ab0de 100644 --- a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs @@ -45,6 +45,8 @@ namespace osu.Game.Overlays.Profile.Header private Bindable coverExpanded = null!; + private FillFlowContainer flow = null!; + [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider, OsuConfigManager configManager) { @@ -77,7 +79,7 @@ namespace osu.Game.Overlays.Profile.Header AutoSizeAxes = Axes.Y, Children = new Drawable[] { - new FillFlowContainer + flow = new FillFlowContainer { Direction = FillDirection.Horizontal, Padding = new MarginPadding @@ -85,7 +87,6 @@ namespace osu.Game.Overlays.Profile.Header Left = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = vertical_padding }, - Spacing = new Vector2(20, 0), Height = content_height + 2 * vertical_padding, RelativeSizeAxes = Axes.X, Children = new Drawable[] @@ -219,9 +220,12 @@ namespace osu.Game.Overlays.Profile.Header { const float transition_duration = 250; - cover.ResizeHeightTo(coverToggle.CoverExpanded.Value ? 250 : 0, transition_duration, Easing.OutQuint); - avatar.ResizeTo(new Vector2(coverToggle.CoverExpanded.Value ? 120 : content_height), transition_duration, Easing.OutQuint); - avatar.TransformTo(nameof(avatar.CornerRadius), coverToggle.CoverExpanded.Value ? 40f : 20f, transition_duration, Easing.OutQuint); + bool expanded = coverToggle.CoverExpanded.Value; + + cover.ResizeHeightTo(expanded ? 250 : 0, transition_duration, Easing.OutQuint); + avatar.ResizeTo(new Vector2(expanded ? 120 : content_height), transition_duration, Easing.OutQuint); + avatar.TransformTo(nameof(avatar.CornerRadius), expanded ? 40f : 20f, transition_duration, Easing.OutQuint); + flow.TransformTo(nameof(flow.Spacing), new Vector2(expanded ? 20f : 10f), transition_duration, Easing.OutQuint); } private partial class ProfileCoverBackground : UserCoverBackground From 6bf7773532c117791c67451bae8280b84f2748cb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Jan 2023 14:27:54 +0900 Subject: [PATCH 176/430] Increase duration of expansion transition --- osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs index 57197ab0de..652ebcec26 100644 --- a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs @@ -218,7 +218,7 @@ namespace osu.Game.Overlays.Profile.Header private void updateCoverState() { - const float transition_duration = 250; + const float transition_duration = 500; bool expanded = coverToggle.CoverExpanded.Value; From 598c6fcbad58333eee5f0ab6e515989ba53ae308 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Jan 2023 15:48:57 +0900 Subject: [PATCH 177/430] Add basic support for stupidly long hold note skin textures --- .../special-skin/LongNoteTailWang.png | Bin 0 -> 101181 bytes .../Resources/special-skin/skin.ini | 4 +- .../Skinning/Legacy/LegacyBodyPiece.cs | 6 +- osu.Game/Skinning/Skin.cs | 56 +++++++++++++++++- 4 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 osu.Game.Rulesets.Mania.Tests/Resources/special-skin/LongNoteTailWang.png diff --git a/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/LongNoteTailWang.png b/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/LongNoteTailWang.png new file mode 100644 index 0000000000000000000000000000000000000000..982cc1d259efcd670f0e7baf338a11059c7b098c GIT binary patch literal 101181 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
  • m@nicEnXm?)|Fu4vV*{ZH((wm)g|Fp## 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 literal 0 HcmV?d00001 diff --git a/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/skin.ini b/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/skin.ini index 9c987efc60..7c51036d69 100644 --- a/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/skin.ini +++ b/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/skin.ini @@ -14,4 +14,6 @@ Hit200: mania/hit200@2x Hit300: mania/hit300@2x Hit300g: mania/hit300g@2x StageLeft: mania/stage-left -StageRight: mania/stage-right \ No newline at end of file +StageRight: mania/stage-right +NoteImage0L: LongNoteTailWang +NoteImage1L: LongNoteTailWang diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs index c928ebb3e0..6887674a1f 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs @@ -54,6 +54,9 @@ 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); @@ -92,7 +95,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy d.RelativeSizeAxes = Axes.Both; d.Size = Vector2.One; d.FillMode = FillMode.Stretch; - // Todo: Wrap + d.Height = minimumColumnWidth / d.DrawWidth * 1.6f; + // Todo: Wrap? }); if (bodySprite != null) diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index 19e8bc7092..2761a93290 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -7,9 +7,12 @@ using System.Diagnostics; using System.IO; using System.Linq; using System.Text; +using System.Threading; +using System.Threading.Tasks; using Newtonsoft.Json; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; @@ -18,6 +21,8 @@ using osu.Game.Audio; using osu.Game.Database; using osu.Game.IO; using osu.Game.Screens.Play.HUD; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Processing; namespace osu.Game.Skinning { @@ -77,7 +82,7 @@ namespace osu.Game.Skinning (storage as ResourceStore)?.AddExtension("ogg"); Samples = samples; - Textures = new TextureStore(resources.Renderer, resources.CreateTextureLoaderStore(storage)); + Textures = new TextureStore(resources.Renderer, new SquishingTextureLoaderStore(resources.CreateTextureLoaderStore(storage))); } else { @@ -210,5 +215,54 @@ namespace osu.Game.Skinning } #endregion + + public class SquishingTextureLoaderStore : IResourceStore + { + private readonly IResourceStore textureStore; + + public SquishingTextureLoaderStore(IResourceStore textureStore) + { + this.textureStore = textureStore; + } + + public void Dispose() + { + textureStore.Dispose(); + } + + public TextureUpload Get(string name) + { + var textureUpload = textureStore.Get(name); + + // NRT not enabled on framework side classes (IResourceStore / TextureLoaderStore), welp. + if (textureUpload.IsNull()) + return null!; + + // So there's a thing where some users have taken it upon themselves to create skin elements of insane dimensions. + // To the point where GPUs cannot load the textures (along with most image editor apps). + // To work around this, let's look out for any stupid images and shrink them down into a usable size. + const int max_supported_texture_size = 16384; + + if (textureUpload.Height > max_supported_texture_size || textureUpload.Width > max_supported_texture_size) + { + var image = Image.LoadPixelData(textureUpload.Data.ToArray(), textureUpload.Width, textureUpload.Height); + + image.Mutate(i => i.Resize(new Size( + Math.Min(textureUpload.Width, max_supported_texture_size), + Math.Min(textureUpload.Height, max_supported_texture_size) + ))); + + return new TextureUpload(image); + } + + return textureUpload; + } + + public Task GetAsync(string name, CancellationToken cancellationToken = new CancellationToken()) => textureStore.GetAsync(name, cancellationToken); + + public Stream GetStream(string name) => textureStore.GetStream(name); + + public IEnumerable GetAvailableResources() => textureStore.GetAvailableResources(); + } } } From d000a4ed28967ef7a40c541acb26df6969c82373 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Jan 2023 15:56:10 +0900 Subject: [PATCH 178/430] Make sure to dispose of the original texture upload as we are replacing it --- osu.Game/Skinning/Skin.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index 2761a93290..298a94920f 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -247,6 +247,9 @@ namespace osu.Game.Skinning { var image = Image.LoadPixelData(textureUpload.Data.ToArray(), textureUpload.Width, textureUpload.Height); + // The original texture upload will no longer be returned or used. + textureUpload.Dispose(); + image.Mutate(i => i.Resize(new Size( Math.Min(textureUpload.Width, max_supported_texture_size), Math.Min(textureUpload.Height, max_supported_texture_size) From c1a5c16973d2a0a62b7393e5d647e2035793fa0a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Jan 2023 16:39:03 +0900 Subject: [PATCH 179/430] Reduce maximum texture size to a more commonly-supported `8192` --- 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 298a94920f..c862a51870 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -241,7 +241,7 @@ namespace osu.Game.Skinning // So there's a thing where some users have taken it upon themselves to create skin elements of insane dimensions. // To the point where GPUs cannot load the textures (along with most image editor apps). // To work around this, let's look out for any stupid images and shrink them down into a usable size. - const int max_supported_texture_size = 16384; + const int max_supported_texture_size = 8192; if (textureUpload.Height > max_supported_texture_size || textureUpload.Width > max_supported_texture_size) { From 0a9b20d5d5f3a734e8b8f25dcefe8d6d08a41c22 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Jan 2023 20:01:00 +0900 Subject: [PATCH 180/430] Split lookup store into own file / class --- .../MaxDimensionLimitedTextureLoaderStore.cs | 69 ++++++++++++++++ osu.Game/Skinning/Skin.cs | 80 +++---------------- 2 files changed, 82 insertions(+), 67 deletions(-) create mode 100644 osu.Game/Skinning/MaxDimensionLimitedTextureLoaderStore.cs diff --git a/osu.Game/Skinning/MaxDimensionLimitedTextureLoaderStore.cs b/osu.Game/Skinning/MaxDimensionLimitedTextureLoaderStore.cs new file mode 100644 index 0000000000..94d7afaf7e --- /dev/null +++ b/osu.Game/Skinning/MaxDimensionLimitedTextureLoaderStore.cs @@ -0,0 +1,69 @@ +// 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; +using System.Threading; +using System.Threading.Tasks; +using osu.Framework.Graphics.Textures; +using osu.Framework.IO.Stores; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Processing; + +namespace osu.Game.Skinning +{ + public class MaxDimensionLimitedTextureLoaderStore : IResourceStore + { + private readonly IResourceStore textureStore; + + public MaxDimensionLimitedTextureLoaderStore(IResourceStore textureStore) + { + this.textureStore = textureStore; + } + + public void Dispose() + { + textureStore?.Dispose(); + } + + public TextureUpload Get(string name) + { + var textureUpload = textureStore?.Get(name); + + // NRT not enabled on framework side classes (IResourceStore / TextureLoaderStore), welp. + if (textureUpload == null) + return null!; + + // So there's a thing where some users have taken it upon themselves to create skin elements of insane dimensions. + // To the point where GPUs cannot load the textures (along with most image editor apps). + // To work around this, let's look out for any stupid images and shrink them down into a usable size. + const int max_supported_texture_size = 8192; + + if (textureUpload.Height > max_supported_texture_size || textureUpload.Width > max_supported_texture_size) + { + var image = Image.LoadPixelData(textureUpload.Data.ToArray(), textureUpload.Width, textureUpload.Height); + + // The original texture upload will no longer be returned or used. + textureUpload.Dispose(); + + image.Mutate(i => i.Resize(new Size( + Math.Min(textureUpload.Width, max_supported_texture_size), + Math.Min(textureUpload.Height, max_supported_texture_size) + ))); + + return new TextureUpload(image); + } + + return textureUpload; + } + + public Task GetAsync(string name, CancellationToken cancellationToken = new CancellationToken()) => textureStore?.GetAsync(name, cancellationToken); + + public Stream GetStream(string name) => textureStore?.GetStream(name) ?? default; + + public IEnumerable GetAvailableResources() => textureStore?.GetAvailableResources(); + } +} diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index c862a51870..cc302a8b1e 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -1,18 +1,17 @@ // 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.Diagnostics; using System.IO; using System.Linq; using System.Text; -using System.Threading; -using System.Threading.Tasks; using Newtonsoft.Json; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; -using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; @@ -21,8 +20,6 @@ using osu.Game.Audio; using osu.Game.Database; using osu.Game.IO; using osu.Game.Screens.Play.HUD; -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Processing; namespace osu.Game.Skinning { @@ -31,12 +28,12 @@ namespace osu.Game.Skinning /// /// A texture store which can be used to perform user file lookups for this skin. /// - protected TextureStore? Textures { get; } + protected TextureStore Textures { get; } /// /// A sample store which can be used to perform user file lookups for this skin. /// - protected ISampleStore? Samples { get; } + protected ISampleStore Samples { get; } public readonly Live SkinInfo; @@ -46,17 +43,17 @@ namespace osu.Game.Skinning private readonly Dictionary drawableComponentInfo = new Dictionary(); - public abstract ISample? GetSample(ISampleInfo sampleInfo); + public abstract ISample GetSample(ISampleInfo sampleInfo); - public Texture? GetTexture(string componentName) => GetTexture(componentName, default, default); + public Texture GetTexture(string componentName) => GetTexture(componentName, default, default); - public abstract Texture? GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT); + public abstract Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT); - public abstract IBindable? GetConfig(TLookup lookup) + public abstract IBindable GetConfig(TLookup lookup) where TLookup : notnull where TValue : notnull; - private readonly RealmBackedResourceStore? realmBackedStorage; + private readonly RealmBackedResourceStore realmBackedStorage; /// /// Construct a new skin. @@ -65,7 +62,7 @@ namespace osu.Game.Skinning /// Access to game-wide resources. /// An optional store which will *replace* all file lookups that are usually sourced from . /// An optional filename to read the skin configuration from. If not provided, the configuration will be retrieved from the storage using "skin.ini". - protected Skin(SkinInfo skin, IStorageResourceProvider? resources, IResourceStore? storage = null, string configurationFilename = @"skin.ini") + protected Skin(SkinInfo skin, IStorageResourceProvider resources, IResourceStore storage = null, string configurationFilename = @"skin.ini") { if (resources != null) { @@ -82,7 +79,7 @@ namespace osu.Game.Skinning (storage as ResourceStore)?.AddExtension("ogg"); Samples = samples; - Textures = new TextureStore(resources.Renderer, new SquishingTextureLoaderStore(resources.CreateTextureLoaderStore(storage))); + Textures = new TextureStore(resources.Renderer, new MaxDimensionLimitedTextureLoaderStore(resources.CreateTextureLoaderStore(storage))); } else { @@ -106,7 +103,7 @@ namespace osu.Game.Skinning { string filename = $"{skinnableTarget}.json"; - byte[]? bytes = storage?.Get(filename); + byte[] bytes = storage?.Get(filename); if (bytes == null) continue; @@ -159,7 +156,7 @@ namespace osu.Game.Skinning DrawableComponentInfo[targetContainer.Target] = targetContainer.CreateSkinnableInfo().ToArray(); } - public virtual Drawable? GetDrawableComponent(ISkinComponentLookup lookup) + public virtual Drawable GetDrawableComponent(ISkinComponentLookup lookup) { switch (lookup) { @@ -216,56 +213,5 @@ namespace osu.Game.Skinning #endregion - public class SquishingTextureLoaderStore : IResourceStore - { - private readonly IResourceStore textureStore; - - public SquishingTextureLoaderStore(IResourceStore textureStore) - { - this.textureStore = textureStore; - } - - public void Dispose() - { - textureStore.Dispose(); - } - - public TextureUpload Get(string name) - { - var textureUpload = textureStore.Get(name); - - // NRT not enabled on framework side classes (IResourceStore / TextureLoaderStore), welp. - if (textureUpload.IsNull()) - return null!; - - // So there's a thing where some users have taken it upon themselves to create skin elements of insane dimensions. - // To the point where GPUs cannot load the textures (along with most image editor apps). - // To work around this, let's look out for any stupid images and shrink them down into a usable size. - const int max_supported_texture_size = 8192; - - if (textureUpload.Height > max_supported_texture_size || textureUpload.Width > max_supported_texture_size) - { - var image = Image.LoadPixelData(textureUpload.Data.ToArray(), textureUpload.Width, textureUpload.Height); - - // The original texture upload will no longer be returned or used. - textureUpload.Dispose(); - - image.Mutate(i => i.Resize(new Size( - Math.Min(textureUpload.Width, max_supported_texture_size), - Math.Min(textureUpload.Height, max_supported_texture_size) - ))); - - return new TextureUpload(image); - } - - return textureUpload; - } - - public Task GetAsync(string name, CancellationToken cancellationToken = new CancellationToken()) => textureStore.GetAsync(name, cancellationToken); - - public Stream GetStream(string name) => textureStore.GetStream(name); - - public IEnumerable GetAvailableResources() => textureStore.GetAvailableResources(); - } } } From 8caf960f9ad5e4d1e92cbdef6dd75ad5dd520b63 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Jan 2023 13:21:44 +0900 Subject: [PATCH 181/430] Revert weird nullable changes to `Skin.cs` --- osu.Game/Skinning/Skin.cs | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index cc302a8b1e..419dacadfd 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.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.Diagnostics; @@ -28,12 +26,12 @@ namespace osu.Game.Skinning /// /// A texture store which can be used to perform user file lookups for this skin. /// - protected TextureStore Textures { get; } + protected TextureStore? Textures { get; } /// /// A sample store which can be used to perform user file lookups for this skin. /// - protected ISampleStore Samples { get; } + protected ISampleStore? Samples { get; } public readonly Live SkinInfo; @@ -43,17 +41,17 @@ namespace osu.Game.Skinning private readonly Dictionary drawableComponentInfo = new Dictionary(); - public abstract ISample GetSample(ISampleInfo sampleInfo); + public abstract ISample? GetSample(ISampleInfo sampleInfo); - public Texture GetTexture(string componentName) => GetTexture(componentName, default, default); + public Texture? GetTexture(string componentName) => GetTexture(componentName, default, default); - public abstract Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT); + public abstract Texture? GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT); - public abstract IBindable GetConfig(TLookup lookup) + public abstract IBindable? GetConfig(TLookup lookup) where TLookup : notnull where TValue : notnull; - private readonly RealmBackedResourceStore realmBackedStorage; + private readonly RealmBackedResourceStore? realmBackedStorage; /// /// Construct a new skin. @@ -62,7 +60,7 @@ namespace osu.Game.Skinning /// Access to game-wide resources. /// An optional store which will *replace* all file lookups that are usually sourced from . /// An optional filename to read the skin configuration from. If not provided, the configuration will be retrieved from the storage using "skin.ini". - protected Skin(SkinInfo skin, IStorageResourceProvider resources, IResourceStore storage = null, string configurationFilename = @"skin.ini") + protected Skin(SkinInfo skin, IStorageResourceProvider? resources, IResourceStore? storage = null, string configurationFilename = @"skin.ini") { if (resources != null) { @@ -103,7 +101,7 @@ namespace osu.Game.Skinning { string filename = $"{skinnableTarget}.json"; - byte[] bytes = storage?.Get(filename); + byte[]? bytes = storage?.Get(filename); if (bytes == null) continue; @@ -156,7 +154,7 @@ namespace osu.Game.Skinning DrawableComponentInfo[targetContainer.Target] = targetContainer.CreateSkinnableInfo().ToArray(); } - public virtual Drawable GetDrawableComponent(ISkinComponentLookup lookup) + public virtual Drawable? GetDrawableComponent(ISkinComponentLookup lookup) { switch (lookup) { @@ -212,6 +210,5 @@ namespace osu.Game.Skinning } #endregion - } } From 7bb6337d2ef8111784c7d7f4c6697748d5f6d53f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Jan 2023 13:24:45 +0900 Subject: [PATCH 182/430] Fix nullability (thanks bdach for patch) --- .../MaxDimensionLimitedTextureLoaderStore.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Skinning/MaxDimensionLimitedTextureLoaderStore.cs b/osu.Game/Skinning/MaxDimensionLimitedTextureLoaderStore.cs index 94d7afaf7e..503add45ed 100644 --- a/osu.Game/Skinning/MaxDimensionLimitedTextureLoaderStore.cs +++ b/osu.Game/Skinning/MaxDimensionLimitedTextureLoaderStore.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; @@ -17,9 +15,9 @@ namespace osu.Game.Skinning { public class MaxDimensionLimitedTextureLoaderStore : IResourceStore { - private readonly IResourceStore textureStore; + private readonly IResourceStore? textureStore; - public MaxDimensionLimitedTextureLoaderStore(IResourceStore textureStore) + public MaxDimensionLimitedTextureLoaderStore(IResourceStore? textureStore) { this.textureStore = textureStore; } @@ -60,10 +58,12 @@ namespace osu.Game.Skinning return textureUpload; } - public Task GetAsync(string name, CancellationToken cancellationToken = new CancellationToken()) => textureStore?.GetAsync(name, cancellationToken); + // TODO: remove null-forgiving operator below after texture stores are NRT-annotated framework-side + public Task GetAsync(string name, CancellationToken cancellationToken = new CancellationToken()) + => textureStore?.GetAsync(name, cancellationToken) ?? Task.FromResult(null!); - public Stream GetStream(string name) => textureStore?.GetStream(name) ?? default; + public Stream? GetStream(string name) => textureStore?.GetStream(name); - public IEnumerable GetAvailableResources() => textureStore?.GetAvailableResources(); + public IEnumerable GetAvailableResources() => textureStore?.GetAvailableResources() ?? Array.Empty(); } } From 5bfd4e47a1b548626bee48e1a0b6edf6c148dd12 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Jan 2023 14:59:54 +0900 Subject: [PATCH 183/430] Refactor position tracking touch handling (and comments) to read better --- .../UI/OsuTouchInputMapper.cs | 59 +++++++++++++------ 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs index 2e4f983fc4..7ff85f46a5 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs @@ -59,27 +59,11 @@ namespace osu.Game.Rulesets.Osu.UI // This case gets special handling to allow for empty-space stream tapping. bool isDirectCircleTouch = osuInputManager.CheckScreenSpaceActionPressJudgeable(e.ScreenSpaceTouchDownPosition); - var trackedTouch = new TrackedTouch(e.Touch.Source, shouldResultInAction ? action : null, isDirectCircleTouch); + var newTouch = new TrackedTouch(e.Touch.Source, shouldResultInAction ? action : null, isDirectCircleTouch); - if (isDirectCircleTouch) - positionTrackingTouch = trackedTouch; - else - { - // If no direct touch is registered, we always use the new (latest) touch for positional tracking. - if (positionTrackingTouch?.DirectTouch != true) - positionTrackingTouch = trackedTouch; - else - { - // If not a direct circle touch, consider whether to release the an original direct touch. - if (positionTrackingTouch.DirectTouch && positionTrackingTouch.Action is OsuAction directTouchAction) - { - osuInputManager.KeyBindingContainer.TriggerReleased(directTouchAction); - positionTrackingTouch.Action = null; - } - } - } + updatePositionTracking(newTouch); - trackedTouches.Add(trackedTouch); + trackedTouches.Add(newTouch); // Important to update position before triggering the pressed action. handleTouchMovement(e); @@ -90,6 +74,43 @@ namespace osu.Game.Rulesets.Osu.UI return true; } + /// + /// Given a new touch, update the positional tracking state and any related operations. + /// + private void updatePositionTracking(TrackedTouch newTouch) + { + // If the new touch directly interacted with a circle's receptor, it always becomes the current touch for positional tracking. + if (newTouch.DirectTouch) + { + positionTrackingTouch = newTouch; + return; + } + + // Otherwise, we only want to use the new touch for position tracking if no other touch is tracking position yet.. + if (positionTrackingTouch == null) + { + positionTrackingTouch = newTouch; + return; + } + + // ..or if the current position tracking touch was not a direct touch (this one is debatable and may be change in the future, but it's the simplest way to handle) + if (!positionTrackingTouch.DirectTouch) + { + positionTrackingTouch = newTouch; + return; + } + + // In the case the new touch was not used for position tracking, we should also check the previous position tracking touch. + // If it was a direct touch and still has its action pressed, that action should be released. + // + // This is done to allow tracking with the initial touch while still having both Left/Right actions available for alternating with two more touches. + if (positionTrackingTouch.DirectTouch && positionTrackingTouch.Action is OsuAction directTouchAction) + { + osuInputManager.KeyBindingContainer.TriggerReleased(directTouchAction); + positionTrackingTouch.Action = null; + } + } + private void handleTouchMovement(TouchEvent touchEvent) { // Movement should only be tracked for the most recent touch. From e4a79d8581cb52b9e813170d2a68cc205b7cc200 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Jan 2023 15:01:05 +0900 Subject: [PATCH 184/430] Rename test scene to differentiate from other ruleset touch tests --- .../{TestSceneTouchInput.cs => TestSceneOsuTouchInput.cs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename osu.Game.Rulesets.Osu.Tests/{TestSceneTouchInput.cs => TestSceneOsuTouchInput.cs} (99%) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs similarity index 99% rename from osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs rename to osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs index 4589eb88c0..72bcec6045 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs @@ -29,7 +29,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Tests { [TestFixture] - public partial class TestSceneTouchInput : OsuManualInputManagerTestScene + public partial class TestSceneOsuTouchInput : OsuManualInputManagerTestScene { [Resolved] private OsuConfigManager config { get; set; } = null!; From 1cde90d55d8c8a22152dcd0f1cfe291b8b334b58 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Jan 2023 15:03:47 +0900 Subject: [PATCH 185/430] Add note about `CheckScreenSpaceActionPresJudgeable` being naive --- osu.Game.Rulesets.Osu/OsuInputManager.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game.Rulesets.Osu/OsuInputManager.cs b/osu.Game.Rulesets.Osu/OsuInputManager.cs index 465dd13362..ccd388192e 100644 --- a/osu.Game.Rulesets.Osu/OsuInputManager.cs +++ b/osu.Game.Rulesets.Osu/OsuInputManager.cs @@ -43,6 +43,10 @@ namespace osu.Game.Rulesets.Osu => new OsuKeyBindingContainer(ruleset, variant, unique); public bool CheckScreenSpaceActionPressJudgeable(Vector2 screenSpacePosition) => + // This is a very naive but simple approach. + // + // Based on user feedback of more nuanced scenarios (where touch doesn't behave as expected), + // this can be expanded to a more complex implementation, but I'd still want to keep it as simple as we can. NonPositionalInputQueue.OfType().Any(c => c.ReceivePositionalInputAt(screenSpacePosition)); public OsuInputManager(RulesetInfo ruleset) From 9499d3a20a9b5fefff77672410107a9c44ac2392 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Jan 2023 15:50:49 +0900 Subject: [PATCH 186/430] Add support for disabling "hit lighting" with osu! argon skin --- .../TestSceneHitCircle.cs | 12 +++++++ .../Skinning/Argon/ArgonMainCirclePiece.cs | 36 ++++++++++++++----- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs index a418df605f..50f9c5e775 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs @@ -5,9 +5,11 @@ using System.Linq; using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Configuration; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; @@ -22,6 +24,9 @@ namespace osu.Game.Rulesets.Osu.Tests { private int depthIndex; + [Resolved] + private OsuConfigManager config { get; set; } + [Test] public void TestHits() { @@ -56,6 +61,13 @@ namespace osu.Game.Rulesets.Osu.Tests AddStep("Hit stream late", () => SetContents(_ => testStream(5, true, 150))); } + [Test] + public void TestHitLighting() + { + AddToggleStep("toggle hit lighting", v => config.SetValue(OsuSetting.HitLighting, v)); + AddStep("Hit Big Single", () => SetContents(_ => testSingle(2, true))); + } + private Drawable testSingle(float circleSize, bool auto = false, double timeOffset = 0, Vector2? positionOffset = null) { var playfield = new TestOsuPlayfield(); diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs index db458ec48a..ab24f9402a 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; +using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Objects.Drawables; @@ -44,6 +45,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon private readonly IBindable indexInCurrentCombo = new Bindable(); private readonly FlashPiece flash; + private Bindable configHitLighting = null!; + [Resolved] private DrawableHitObject drawableObject { get; set; } = null!; @@ -96,12 +99,14 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon } [BackgroundDependencyLoader] - private void load() + private void load(OsuConfigManager config) { var drawableOsuObject = (DrawableOsuHitObject)drawableObject; accentColour.BindTo(drawableObject.AccentColour); indexInCurrentCombo.BindTo(drawableOsuObject.IndexInCurrentComboBindable); + + configHitLighting = config.GetBindable(OsuSetting.HitLighting); } protected override void LoadComplete() @@ -140,12 +145,15 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon case ArmedState.Hit: // Fade out time is at a maximum of 800. Must match `DrawableHitCircle`'s arbitrary lifetime spec. const double fade_out_time = 800; - const double flash_in_duration = 150; const double resize_duration = 400; const float shrink_size = 0.8f; + // When the user has hit lighting disabled, we won't be showing the bright white flash. + // To make things look good, the surrounding animations are also slightly adjusted. + bool showFlash = configHitLighting.Value; + // Animating with the number present is distracting. // The number disappearing is hidden by the bright flash. number.FadeOut(flash_in_duration / 2); @@ -176,15 +184,27 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon using (BeginDelayedSequence(flash_in_duration / 12)) { outerGradient.ResizeTo(OUTER_GRADIENT_SIZE * shrink_size, resize_duration, Easing.OutElasticHalf); - outerGradient - .FadeColour(Color4.White, 80) - .Then() - .FadeOut(flash_in_duration); + + if (showFlash) + { + outerGradient + .FadeColour(Color4.White, 80) + .Then() + .FadeOut(flash_in_duration); + } + else + { + outerGradient + .FadeColour(Color4.White, flash_in_duration * 8) + .FadeOut(flash_in_duration * 2); + } } - flash.FadeTo(1, flash_in_duration, Easing.OutQuint); + if (showFlash) + flash.FadeTo(1, flash_in_duration, Easing.OutQuint); + + this.FadeOut(showFlash ? fade_out_time : fade_out_time / 2, Easing.OutQuad); - this.FadeOut(fade_out_time, Easing.OutQuad); break; } } From f81dea4166baf3bc7d0816d82df62c2efac8e075 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Jan 2023 16:24:52 +0900 Subject: [PATCH 187/430] Remove now unused localisation string --- osu.Game/Localisation/UserInterfaceStrings.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/osu.Game/Localisation/UserInterfaceStrings.cs b/osu.Game/Localisation/UserInterfaceStrings.cs index fb9eeeb3de..ea664d7b50 100644 --- a/osu.Game/Localisation/UserInterfaceStrings.cs +++ b/osu.Game/Localisation/UserInterfaceStrings.cs @@ -109,11 +109,6 @@ namespace osu.Game.Localisation /// public static LocalisableString ModSelectHotkeyStyle => new TranslatableString(getKey(@"mod_select_hotkey_style"), @"Mod select hotkey style"); - /// - /// "Background blur" - /// - public static LocalisableString BackgroundBlurLevel => new TranslatableString(getKey(@"background_blur_level"), @"Background blur"); - /// /// "no limit" /// From 1a9ed1ac3fa56473f5b2aaa586ba7f747de291ef Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Jan 2023 16:28:06 +0900 Subject: [PATCH 188/430] Remove unnecessary `IgnoreUserSettings` value change --- osu.Game/Screens/Select/SongSelect.cs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 505f932bff..680c740b01 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -133,15 +133,11 @@ namespace osu.Game.Screens.Select configBackgroundBlur = config.GetBindable(OsuSetting.SongSelectBackgoundBlur); configBackgroundBlur.BindValueChanged(e => { - if (this.IsCurrentScreen()) - { - ApplyToBackground(background => - { - background.IgnoreUserSettings.Value = true; - background.BlurAmount.Value = e.NewValue ? BACKGROUND_BLUR : 0; - }); - } - }, true); + if (!this.IsCurrentScreen()) + return; + + ApplyToBackground(b => b.BlurAmount.Value = e.NewValue ? BACKGROUND_BLUR : 0); + }); LoadComponentAsync(Carousel = new BeatmapCarousel { From e333e12b2ec1e0d5985c57d6ad94b858627690fc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Jan 2023 16:28:38 +0900 Subject: [PATCH 189/430] Fix typo in settings enum (seriously) --- osu.Game/Configuration/OsuConfigManager.cs | 4 ++-- .../Settings/Sections/UserInterface/SongSelectSettings.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index fff5dc62c6..1c1745b55d 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -60,7 +60,7 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.ToolbarClockDisplayMode, ToolbarClockDisplayMode.Full); - SetDefault(OsuSetting.SongSelectBackgoundBlur, true); + SetDefault(OsuSetting.SongSelectBackgroundBlur, true); // Online settings SetDefault(OsuSetting.Username, string.Empty); @@ -341,7 +341,7 @@ namespace osu.Game.Configuration ChatDisplayHeight, BeatmapListingCardSize, ToolbarClockDisplayMode, - SongSelectBackgoundBlur, + SongSelectBackgroundBlur, Version, ShowFirstRunSetup, ShowConvertedBeatmaps, diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs index d40d24a528..6f30fcd100 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs @@ -46,7 +46,7 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface new SettingsCheckbox { LabelText = GameplaySettingsStrings.BackgroundBlur, - Current = config.GetBindable(OsuSetting.SongSelectBackgoundBlur) + Current = config.GetBindable(OsuSetting.SongSelectBackgroundBlur) } }; } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 680c740b01..41e722ae88 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -130,7 +130,7 @@ namespace osu.Game.Screens.Select [BackgroundDependencyLoader(true)] private void load(AudioManager audio, OsuColour colours, ManageCollectionsDialog? manageCollectionsDialog, DifficultyRecommender? recommender, OsuConfigManager config) { - configBackgroundBlur = config.GetBindable(OsuSetting.SongSelectBackgoundBlur); + configBackgroundBlur = config.GetBindable(OsuSetting.SongSelectBackgroundBlur); configBackgroundBlur.BindValueChanged(e => { if (!this.IsCurrentScreen()) From 01e280eb6bba20f85b49e98379550ad20906822c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Jan 2023 16:31:41 +0900 Subject: [PATCH 190/430] Add classic default for song select blur setting --- .../Settings/Sections/UserInterface/SongSelectSettings.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs index 6f30fcd100..d3303e409c 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs @@ -46,7 +46,8 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface new SettingsCheckbox { LabelText = GameplaySettingsStrings.BackgroundBlur, - Current = config.GetBindable(OsuSetting.SongSelectBackgroundBlur) + Current = config.GetBindable(OsuSetting.SongSelectBackgroundBlur), + ClassicDefault = false, } }; } From d15f8c2f3a1ffb79fb1fcfd2e0ee2717b2c0cbb0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Jan 2023 17:11:14 +0900 Subject: [PATCH 191/430] Fix beatmaps with multiple `osb` files potentially reading the storyboard from the wrong one In stable, the storyboard filename is fixed. In lazer, we were always looking for the first `.osb` in the database. In the case a beatmap archive housed more than one `.osb` files, this may load the incorrect one. Using `GetDisplayString` here feels like it could potentially go wrong in the future, so I'm open to hard-coding this locally (or using string manipulation to remove the ` [creator_name]` portion of the beatmap's filename). Open to opinions on that. Fixes storyboard playback in https://osu.ppy.sh/beatmapsets/1913687#osu/3947758 --- osu.Game/Beatmaps/WorkingBeatmapCache.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmapCache.cs b/osu.Game/Beatmaps/WorkingBeatmapCache.cs index e6f96330e7..546f0e6c3a 100644 --- a/osu.Game/Beatmaps/WorkingBeatmapCache.cs +++ b/osu.Game/Beatmaps/WorkingBeatmapCache.cs @@ -20,6 +20,7 @@ using osu.Framework.Statistics; using osu.Framework.Testing; using osu.Game.Beatmaps.Formats; using osu.Game.Database; +using osu.Game.Extensions; using osu.Game.IO; using osu.Game.Skinning; using osu.Game.Storyboards; @@ -268,7 +269,7 @@ namespace osu.Game.Beatmaps Stream storyboardFileStream = null; - if (BeatmapSetInfo?.Files.FirstOrDefault(f => f.Filename.EndsWith(".osb", StringComparison.OrdinalIgnoreCase))?.Filename is string storyboardFilename) + if (BeatmapSetInfo?.Files.FirstOrDefault(f => f.Filename.Equals($"{BeatmapSetInfo.GetDisplayString()}.osb", StringComparison.OrdinalIgnoreCase))?.Filename is string storyboardFilename) { string storyboardFileStorePath = BeatmapSetInfo?.GetPathForFile(storyboardFilename); storyboardFileStream = GetStream(storyboardFileStorePath); From d09d6f31d704c2b69ecdef00579f80261dc7a2e0 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 25 Jan 2023 12:20:51 +0300 Subject: [PATCH 192/430] Implement Masking property for TrianglesBackground --- .../Skinning/Default/TrianglesPiece.cs | 1 + .../TestSceneTrianglesBackground.cs | 7 ++- osu.Game/Graphics/Backgrounds/Triangles.cs | 43 +++++++++++++++---- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/TrianglesPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/TrianglesPiece.cs index f1143cf14d..16cd302b88 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/TrianglesPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/TrianglesPiece.cs @@ -15,6 +15,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default { TriangleScale = 1.2f; HideAlphaDiscrepancies = false; + Masking = false; } protected override void Update() diff --git a/osu.Game.Tests/Visual/Background/TestSceneTrianglesBackground.cs b/osu.Game.Tests/Visual/Background/TestSceneTrianglesBackground.cs index 8a5489f476..378dd99664 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneTrianglesBackground.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneTrianglesBackground.cs @@ -5,6 +5,7 @@ using osu.Game.Graphics.Backgrounds; using osu.Framework.Graphics; using osuTK.Graphics; using osu.Framework.Graphics.Shapes; +using osuTK; namespace osu.Game.Tests.Visual.Background { @@ -25,7 +26,10 @@ namespace osu.Game.Tests.Visual.Background { RelativeSizeAxes = Axes.Both, ColourLight = Color4.White, - ColourDark = Color4.Gray + ColourDark = Color4.Gray, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(0.9f) } }; } @@ -36,6 +40,7 @@ namespace osu.Game.Tests.Visual.Background AddSliderStep("Triangle scale", 0f, 10f, 1f, s => triangles.TriangleScale = s); AddSliderStep("Seed", 0, 1000, 0, s => triangles.Reset(s)); + AddToggleStep("Masking", m => triangles.Masking = m); } } } diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs index d9dff1574f..1fbf9b4dfa 100644 --- a/osu.Game/Graphics/Backgrounds/Triangles.cs +++ b/osu.Game/Graphics/Backgrounds/Triangles.cs @@ -77,6 +77,12 @@ namespace osu.Game.Graphics.Backgrounds set => triangleScale.Value = value; } + /// + /// If enabled, only the portion of triangles that falls within this 's + /// shape is drawn to the screen. + /// + public bool Masking { get; set; } = true; + /// /// Whether we should drop-off alpha values of triangles more quickly to improve /// the visual appearance of fading. This defaults to on as it is generally more @@ -252,6 +258,7 @@ namespace osu.Game.Graphics.Backgrounds private IShader shader; private Texture texture; + private bool masking; private readonly List parts = new List(); private readonly Vector2 triangleSize = new Vector2(1f, equilateral_triangle_ratio) * triangle_size; @@ -271,6 +278,7 @@ namespace osu.Game.Graphics.Backgrounds shader = Source.shader; texture = Source.texture; size = Source.DrawSize; + masking = Source.Masking; parts.Clear(); parts.AddRange(Source.parts); @@ -294,26 +302,45 @@ namespace osu.Game.Graphics.Backgrounds Vector2 relativeSize = Vector2.Divide(triangleSize * particle.Scale, size); Vector2 topLeft = particle.Position - new Vector2(relativeSize.X * 0.5f, 0f); - Vector2 topRight = topLeft + new Vector2(relativeSize.X, 0f); - Vector2 bottomLeft = topLeft + new Vector2(0f, relativeSize.Y); - Vector2 bottomRight = bottomLeft + new Vector2(relativeSize.X, 0f); + + Quad triangleQuad = masking ? clampToDrawable(topLeft, relativeSize) : new Quad(topLeft.X, topLeft.Y, relativeSize.X, relativeSize.Y); var drawQuad = new Quad( - Vector2Extensions.Transform(topLeft * size, DrawInfo.Matrix), - Vector2Extensions.Transform(topRight * size, DrawInfo.Matrix), - Vector2Extensions.Transform(bottomLeft * size, DrawInfo.Matrix), - Vector2Extensions.Transform(bottomRight * size, DrawInfo.Matrix) + Vector2Extensions.Transform(triangleQuad.TopLeft * size, DrawInfo.Matrix), + Vector2Extensions.Transform(triangleQuad.TopRight * size, DrawInfo.Matrix), + Vector2Extensions.Transform(triangleQuad.BottomLeft * size, DrawInfo.Matrix), + Vector2Extensions.Transform(triangleQuad.BottomRight * size, DrawInfo.Matrix) ); ColourInfo colourInfo = DrawColourInfo.Colour; colourInfo.ApplyChild(particle.Colour); - renderer.DrawQuad(texture, drawQuad, colourInfo, vertexAction: vertexBatch.AddAction); + RectangleF textureCoords = new RectangleF( + triangleQuad.TopLeft.X - topLeft.X, + triangleQuad.TopLeft.Y - topLeft.Y, + triangleQuad.Width, + triangleQuad.Height + ) / relativeSize; + + renderer.DrawQuad(texture, drawQuad, colourInfo, new RectangleF(0, 0, 1, 1), vertexBatch.AddAction, textureCoords: textureCoords); } shader.Unbind(); } + private static Quad clampToDrawable(Vector2 topLeft, Vector2 size) + { + float leftClamped = Math.Clamp(topLeft.X, 0f, 1f); + float topClamped = Math.Clamp(topLeft.Y, 0f, 1f); + + return new Quad( + leftClamped, + topClamped, + Math.Clamp(topLeft.X + size.X, 0f, 1f) - leftClamped, + Math.Clamp(topLeft.Y + size.Y, 0f, 1f) - topClamped + ); + } + protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); From 78cfe2f5476ec361f46f93c6376ba46188273093 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Jan 2023 18:46:52 +0900 Subject: [PATCH 193/430] Fix hit circle kiai test scene not always working as expected --- .../TestSceneHitCircleKiai.cs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleKiai.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleKiai.cs index 2c9f1acd2c..718664d649 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleKiai.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleKiai.cs @@ -4,29 +4,38 @@ #nullable disable using NUnit.Framework; +using osu.Framework.Audio; +using osu.Framework.Audio.Track; +using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; namespace osu.Game.Rulesets.Osu.Tests { [TestFixture] - public partial class TestSceneHitCircleKiai : TestSceneHitCircle + public partial class TestSceneHitCircleKiai : TestSceneHitCircle, IBeatSyncProvider { + private ControlPointInfo controlPoints { get; set; } + [SetUp] public void SetUp() => Schedule(() => { - var controlPointInfo = new ControlPointInfo(); + controlPoints = new ControlPointInfo(); - controlPointInfo.Add(0, new TimingControlPoint { BeatLength = 500 }); - controlPointInfo.Add(0, new EffectControlPoint { KiaiMode = true }); + controlPoints.Add(0, new TimingControlPoint { BeatLength = 500 }); + controlPoints.Add(0, new EffectControlPoint { KiaiMode = true }); Beatmap.Value = CreateWorkingBeatmap(new Beatmap { - ControlPointInfo = controlPointInfo + ControlPointInfo = controlPoints }); // track needs to be playing for BeatSyncedContainer to work. Beatmap.Value.Track.Start(); }); + + ChannelAmplitudes IHasAmplitudes.CurrentAmplitudes => new ChannelAmplitudes(); + ControlPointInfo IBeatSyncProvider.ControlPoints => controlPoints; + IClock IBeatSyncProvider.Clock => Clock; } } From 1485a6e00670118ff29dd79912b3ddc29f22a773 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 25 Jan 2023 12:54:30 +0300 Subject: [PATCH 194/430] Make masking false by default --- osu.Game.Rulesets.Osu/Skinning/Default/TrianglesPiece.cs | 1 - osu.Game/Graphics/Backgrounds/Triangles.cs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/TrianglesPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/TrianglesPiece.cs index 16cd302b88..f1143cf14d 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/TrianglesPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/TrianglesPiece.cs @@ -15,7 +15,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default { TriangleScale = 1.2f; HideAlphaDiscrepancies = false; - Masking = false; } protected override void Update() diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs index 1fbf9b4dfa..6750d74a08 100644 --- a/osu.Game/Graphics/Backgrounds/Triangles.cs +++ b/osu.Game/Graphics/Backgrounds/Triangles.cs @@ -81,7 +81,7 @@ namespace osu.Game.Graphics.Backgrounds /// If enabled, only the portion of triangles that falls within this 's /// shape is drawn to the screen. /// - public bool Masking { get; set; } = true; + public bool Masking { get; set; } /// /// Whether we should drop-off alpha values of triangles more quickly to improve From 48d68b0f4f385ca862db266011cb9fffcb5efee7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Jan 2023 18:59:26 +0900 Subject: [PATCH 195/430] Add very basic kiai flash to argon hit circles --- .../Skinning/Argon/ArgonMainCirclePiece.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs index db458ec48a..d50a3eba13 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs @@ -43,6 +43,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon private readonly IBindable accentColour = new Bindable(); private readonly IBindable indexInCurrentCombo = new Bindable(); private readonly FlashPiece flash; + private readonly KiaiFlash kiaiFlash; [Resolved] private DrawableHitObject drawableObject { get; set; } = null!; @@ -82,6 +83,15 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon Anchor = Anchor.Centre, Origin = Anchor.Centre, }, + new CircularContainer + { + Masking = true, + Size = Size, + Child = kiaiFlash = new KiaiFlash + { + RelativeSizeAxes = Axes.Both, + } + }, number = new OsuSpriteText { Font = OsuFont.Default.With(size: 52, weight: FontWeight.Bold), @@ -117,6 +127,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon outerGradient.ClearTransforms(targetMember: nameof(Colour)); outerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue, colour.NewValue.Darken(0.1f)); + kiaiFlash.Colour = colour.NewValue; outerFill.Colour = innerFill.Colour = colour.NewValue.Darken(4); innerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue.Darken(0.5f), colour.NewValue.Darken(0.6f)); flash.Colour = colour.NewValue; From 0eaebfd40a7a67e6ba9bd9f164b56d9140ce02bc Mon Sep 17 00:00:00 2001 From: EXtremeExploit Date: Wed, 25 Jan 2023 10:22:42 -0300 Subject: [PATCH 196/430] 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 a4a94cb96e418cbd6adaffd0e7be75c08636616c Mon Sep 17 00:00:00 2001 From: EXtremeExploit Date: Wed, 25 Jan 2023 14:34:00 -0300 Subject: [PATCH 197/430] Add movement to misses in osu ruleset --- osu.Game/Skinning/LegacyJudgementPieceNew.cs | 5 ++--- osu.Game/Skinning/LegacyJudgementPieceOld.cs | 5 +++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game/Skinning/LegacyJudgementPieceNew.cs b/osu.Game/Skinning/LegacyJudgementPieceNew.cs index 2430e511c4..7fece3e896 100644 --- a/osu.Game/Skinning/LegacyJudgementPieceNew.cs +++ b/osu.Game/Skinning/LegacyJudgementPieceNew.cs @@ -104,9 +104,8 @@ namespace osu.Game.Skinning this.ScaleTo(1.6f); this.ScaleTo(1, 100, Easing.In); - //todo: this only applies to osu! ruleset apparently. - this.MoveTo(new Vector2(0, -2)); - this.MoveToOffset(new Vector2(0, 20), fade_out_delay + fade_out_length, Easing.In); + this.MoveTo(new Vector2(0, -5)); + this.MoveToOffset(new Vector2(0, 80), fade_out_delay + fade_out_length, Easing.In); float rotation = RNG.NextSingle(-8.6f, 8.6f); diff --git a/osu.Game/Skinning/LegacyJudgementPieceOld.cs b/osu.Game/Skinning/LegacyJudgementPieceOld.cs index 796080f4f5..291b28991d 100644 --- a/osu.Game/Skinning/LegacyJudgementPieceOld.cs +++ b/osu.Game/Skinning/LegacyJudgementPieceOld.cs @@ -10,6 +10,8 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Utils; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; +using osuTK; + namespace osu.Game.Skinning { @@ -55,6 +57,9 @@ namespace osu.Game.Skinning this.ScaleTo(1.6f); this.ScaleTo(1, 100, Easing.In); + this.MoveTo(new Vector2(0, -5)); + this.MoveToOffset(new Vector2(0, 80), fade_out_delay + fade_out_length, Easing.In); + float rotation = RNG.NextSingle(-8.6f, 8.6f); this.RotateTo(0); From fc968d1d89887474093ef017c2346777252b4d6c Mon Sep 17 00:00:00 2001 From: EXtremeExploit Date: Wed, 25 Jan 2023 14:38:02 -0300 Subject: [PATCH 198/430] del extra newline --- osu.Game/Skinning/LegacyJudgementPieceOld.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Skinning/LegacyJudgementPieceOld.cs b/osu.Game/Skinning/LegacyJudgementPieceOld.cs index 291b28991d..749edf80db 100644 --- a/osu.Game/Skinning/LegacyJudgementPieceOld.cs +++ b/osu.Game/Skinning/LegacyJudgementPieceOld.cs @@ -12,7 +12,6 @@ using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; using osuTK; - namespace osu.Game.Skinning { public partial class LegacyJudgementPieceOld : CompositeDrawable, IAnimatableJudgement From fd495e87f74d5e6b76d67b9fa2865378b95c562b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 25 Jan 2023 18:37:58 +0100 Subject: [PATCH 199/430] Fix `GetAsync()` not limiting texture dimensions --- .../MaxDimensionLimitedTextureLoaderStore.cs | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/osu.Game/Skinning/MaxDimensionLimitedTextureLoaderStore.cs b/osu.Game/Skinning/MaxDimensionLimitedTextureLoaderStore.cs index 503add45ed..f15097a169 100644 --- a/osu.Game/Skinning/MaxDimensionLimitedTextureLoaderStore.cs +++ b/osu.Game/Skinning/MaxDimensionLimitedTextureLoaderStore.cs @@ -35,6 +35,25 @@ namespace osu.Game.Skinning if (textureUpload == null) return null!; + return limitTextureUploadSize(textureUpload); + } + + public async Task GetAsync(string name, CancellationToken cancellationToken = new CancellationToken()) + { + // NRT not enabled on framework side classes (IResourceStore / TextureLoaderStore), welp. + if (textureStore == null) + return null!; + + var textureUpload = await textureStore.GetAsync(name, cancellationToken).ConfigureAwait(false); + + if (textureUpload == null) + return null!; + + return await Task.Run(() => limitTextureUploadSize(textureUpload), cancellationToken).ConfigureAwait(false); + } + + private TextureUpload limitTextureUploadSize(TextureUpload textureUpload) + { // So there's a thing where some users have taken it upon themselves to create skin elements of insane dimensions. // To the point where GPUs cannot load the textures (along with most image editor apps). // To work around this, let's look out for any stupid images and shrink them down into a usable size. @@ -58,10 +77,6 @@ namespace osu.Game.Skinning return textureUpload; } - // TODO: remove null-forgiving operator below after texture stores are NRT-annotated framework-side - public Task GetAsync(string name, CancellationToken cancellationToken = new CancellationToken()) - => textureStore?.GetAsync(name, cancellationToken) ?? Task.FromResult(null!); - public Stream? GetStream(string name) => textureStore?.GetStream(name); public IEnumerable GetAvailableResources() => textureStore?.GetAvailableResources() ?? Array.Empty(); From 34aa8b872eb38a460b2a726d2f689a5da96c80c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 25 Jan 2023 18:39:26 +0100 Subject: [PATCH 200/430] Mention stable weirdness next to constant --- 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 6887674a1f..05ba2b8f22 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs @@ -95,7 +95,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy d.RelativeSizeAxes = Axes.Both; d.Size = Vector2.One; d.FillMode = FillMode.Stretch; - d.Height = minimumColumnWidth / d.DrawWidth * 1.6f; + d.Height = minimumColumnWidth / d.DrawWidth * 1.6f; // constant matching stable. // Todo: Wrap? }); From a6fc3ce477e400ef30298ef00cd21330d0849b6c Mon Sep 17 00:00:00 2001 From: EXtremeExploit Date: Wed, 25 Jan 2023 20:38:55 -0300 Subject: [PATCH 201/430] bring comment back --- osu.Game/Skinning/LegacyJudgementPieceNew.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Skinning/LegacyJudgementPieceNew.cs b/osu.Game/Skinning/LegacyJudgementPieceNew.cs index 7fece3e896..6be310c419 100644 --- a/osu.Game/Skinning/LegacyJudgementPieceNew.cs +++ b/osu.Game/Skinning/LegacyJudgementPieceNew.cs @@ -104,6 +104,7 @@ namespace osu.Game.Skinning this.ScaleTo(1.6f); this.ScaleTo(1, 100, Easing.In); + //todo: this only applies to osu! ruleset apparently. this.MoveTo(new Vector2(0, -5)); this.MoveToOffset(new Vector2(0, 80), fade_out_delay + fade_out_length, Easing.In); From bcecc49092d08b0f1a775e8fe0a092f382edc491 Mon Sep 17 00:00:00 2001 From: EXtremeExploit Date: Wed, 25 Jan 2023 23:05:11 -0300 Subject: [PATCH 202/430] Only do misses animations on modern skins --- osu.Game/Skinning/LegacyJudgementPieceNew.cs | 21 ++++---------------- osu.Game/Skinning/LegacyJudgementPieceOld.cs | 11 +++++++--- osu.Game/Skinning/LegacySkin.cs | 4 ++-- 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/osu.Game/Skinning/LegacyJudgementPieceNew.cs b/osu.Game/Skinning/LegacyJudgementPieceNew.cs index 6be310c419..5e2bba9ccd 100644 --- a/osu.Game/Skinning/LegacyJudgementPieceNew.cs +++ b/osu.Game/Skinning/LegacyJudgementPieceNew.cs @@ -17,6 +17,7 @@ namespace osu.Game.Skinning public partial class LegacyJudgementPieceNew : CompositeDrawable, IAnimatableJudgement { private readonly HitResult result; + private readonly decimal? version; private readonly LegacyJudgementPieceOld? temporaryOldStyle; @@ -24,9 +25,10 @@ namespace osu.Game.Skinning private readonly ParticleExplosion? particles; - public LegacyJudgementPieceNew(HitResult result, Func createMainDrawable, Texture? particleTexture) + public LegacyJudgementPieceNew(HitResult result, decimal? version, Func createMainDrawable, Texture? particleTexture) { this.result = result; + this.version = version; AutoSizeAxes = Axes.Both; Origin = Anchor.Centre; @@ -54,7 +56,7 @@ namespace osu.Game.Skinning if (result != HitResult.Miss) { //new judgement shows old as a temporary effect - AddInternal(temporaryOldStyle = new LegacyJudgementPieceOld(result, createMainDrawable, 1.05f, true) + AddInternal(temporaryOldStyle = new LegacyJudgementPieceOld(result, this.version, createMainDrawable, 1.05f, true) { Blending = BlendingParameters.Additive, Anchor = Anchor.Centre, @@ -100,21 +102,6 @@ namespace osu.Game.Skinning switch (result) { - case HitResult.Miss: - this.ScaleTo(1.6f); - this.ScaleTo(1, 100, Easing.In); - - //todo: this only applies to osu! ruleset apparently. - this.MoveTo(new Vector2(0, -5)); - this.MoveToOffset(new Vector2(0, 80), fade_out_delay + fade_out_length, Easing.In); - - float rotation = RNG.NextSingle(-8.6f, 8.6f); - - this.RotateTo(0); - this.RotateTo(rotation, fade_in_length) - .Then().RotateTo(rotation * 2, fade_out_delay + fade_out_length - fade_in_length, Easing.In); - break; - default: mainPiece.ScaleTo(0.9f); mainPiece.ScaleTo(1.05f, fade_out_delay + fade_out_length); diff --git a/osu.Game/Skinning/LegacyJudgementPieceOld.cs b/osu.Game/Skinning/LegacyJudgementPieceOld.cs index 749edf80db..e427e19a6b 100644 --- a/osu.Game/Skinning/LegacyJudgementPieceOld.cs +++ b/osu.Game/Skinning/LegacyJudgementPieceOld.cs @@ -17,13 +17,15 @@ namespace osu.Game.Skinning public partial class LegacyJudgementPieceOld : CompositeDrawable, IAnimatableJudgement { private readonly HitResult result; + private readonly decimal? version; private readonly float finalScale; private readonly bool forceTransforms; - public LegacyJudgementPieceOld(HitResult result, Func createMainDrawable, float finalScale = 1f, bool forceTransforms = false) + public LegacyJudgementPieceOld(HitResult result, decimal? version, Func createMainDrawable, float finalScale = 1f, bool forceTransforms = false) { this.result = result; + this.version = version; this.finalScale = finalScale; this.forceTransforms = forceTransforms; @@ -56,8 +58,11 @@ namespace osu.Game.Skinning this.ScaleTo(1.6f); this.ScaleTo(1, 100, Easing.In); - this.MoveTo(new Vector2(0, -5)); - this.MoveToOffset(new Vector2(0, 80), fade_out_delay + fade_out_length, Easing.In); + if (this.version > 1) + { + this.MoveTo(new Vector2(0, -5)); + this.MoveToOffset(new Vector2(0, 80), fade_out_delay + fade_out_length, Easing.In); + } float rotation = RNG.NextSingle(-8.6f, 8.6f); diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 5f12d2ce23..0942966b1c 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -390,9 +390,9 @@ namespace osu.Game.Skinning var particle = getParticleTexture(resultComponent.Component); if (particle != null) - return new LegacyJudgementPieceNew(resultComponent.Component, createDrawable, particle); + return new LegacyJudgementPieceNew(resultComponent.Component, this.Configuration.LegacyVersion, createDrawable, particle); - return new LegacyJudgementPieceOld(resultComponent.Component, createDrawable); + return new LegacyJudgementPieceOld(resultComponent.Component, this.Configuration.LegacyVersion, createDrawable); } return null; From 7cc4fd4efc9fce06a9705152234bd12c7657c3c2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Jan 2023 15:09:36 +0900 Subject: [PATCH 203/430] Use the exact method stable uses for generating storyboard filenames --- osu.Game/Beatmaps/WorkingBeatmapCache.cs | 33 ++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmapCache.cs b/osu.Game/Beatmaps/WorkingBeatmapCache.cs index 546f0e6c3a..76a31a6f78 100644 --- a/osu.Game/Beatmaps/WorkingBeatmapCache.cs +++ b/osu.Game/Beatmaps/WorkingBeatmapCache.cs @@ -20,7 +20,6 @@ using osu.Framework.Statistics; using osu.Framework.Testing; using osu.Game.Beatmaps.Formats; using osu.Game.Database; -using osu.Game.Extensions; using osu.Game.IO; using osu.Game.Skinning; using osu.Game.Storyboards; @@ -269,7 +268,10 @@ namespace osu.Game.Beatmaps Stream storyboardFileStream = null; - if (BeatmapSetInfo?.Files.FirstOrDefault(f => f.Filename.Equals($"{BeatmapSetInfo.GetDisplayString()}.osb", StringComparison.OrdinalIgnoreCase))?.Filename is string storyboardFilename) + string mainStoryboardFilename = getMainStoryboardFilename(BeatmapSetInfo.Metadata); + + if (BeatmapSetInfo?.Files.FirstOrDefault(f => f.Filename.Equals(mainStoryboardFilename, StringComparison.OrdinalIgnoreCase))?.Filename is string + storyboardFilename) { string storyboardFileStorePath = BeatmapSetInfo?.GetPathForFile(storyboardFilename); storyboardFileStream = GetStream(storyboardFileStorePath); @@ -313,6 +315,33 @@ namespace osu.Game.Beatmaps } public override Stream GetStream(string storagePath) => resources.Files.GetStream(storagePath); + + private string getMainStoryboardFilename(IBeatmapMetadataInfo metadata) + { + // Matches stable implementation, because it's probably simpler than trying to do anything else. + // This may need to be reconsidered after we begin storing storyboards in the new editor. + return windowsFilenameStrip( + (metadata.Artist.Length > 0 ? metadata.Artist + @" - " + metadata.Title : Path.GetFileNameWithoutExtension(metadata.AudioFile)) + + (metadata.Author.Username.Length > 0 ? @" (" + metadata.Author.Username + @")" : string.Empty) + + @".osb"); + + string windowsFilenameStrip(string entry) + { + // Inlined from Path.GetInvalidFilenameChars() to ensure the windows characters are used (to match stable). + char[] invalidCharacters = + { + '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', + '\x08', '\x09', '\x0A', '\x0B', '\x0C', '\x0D', '\x0E', '\x0F', '\x10', '\x11', '\x12', + '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1A', '\x1B', '\x1C', '\x1D', + '\x1E', '\x1F', '\x22', '\x3C', '\x3E', '\x7C', ':', '*', '?', '\\', '/' + }; + + foreach (char c in invalidCharacters) + entry = entry.Replace(c.ToString(), string.Empty); + + return entry; + } + } } } } From de1d473d2908527a903f12fed42713b359aac81a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Jan 2023 15:24:10 +0900 Subject: [PATCH 204/430] Fix kiai flash being visible and incorrectly sized during hit animation --- .../Skinning/Argon/ArgonMainCirclePiece.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs index 04a4d4bede..e7e6e26b5e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs @@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon private readonly IBindable accentColour = new Bindable(); private readonly IBindable indexInCurrentCombo = new Bindable(); private readonly FlashPiece flash; - private readonly KiaiFlash kiaiFlash; + private readonly Container kiaiContainer; private Bindable configHitLighting = null!; @@ -83,11 +83,13 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon Anchor = Anchor.Centre, Origin = Anchor.Centre, }, - new CircularContainer + kiaiContainer = new CircularContainer { Masking = true, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, Size = Size, - Child = kiaiFlash = new KiaiFlash + Child = new KiaiFlash { RelativeSizeAxes = Axes.Both, } @@ -129,7 +131,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon outerGradient.ClearTransforms(targetMember: nameof(Colour)); outerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue, colour.NewValue.Darken(0.1f)); - kiaiFlash.Colour = colour.NewValue; + kiaiContainer.Colour = colour.NewValue; outerFill.Colour = innerFill.Colour = colour.NewValue.Darken(4); innerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue.Darken(0.5f), colour.NewValue.Darken(0.6f)); flash.Colour = colour.NewValue; @@ -191,6 +193,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon // gradient layers. border.ResizeTo(Size * shrink_size + new Vector2(border.BorderThickness), resize_duration, Easing.OutElasticHalf); + // Kiai flash should track the overall size but also be cleaned up quite fast, so we don't get additional + // flashes after the hit animation is already in a mostly-completed state. + kiaiContainer.ResizeTo(Size * shrink_size, resize_duration, Easing.OutElasticHalf); + kiaiContainer.FadeOut(flash_in_duration, Easing.OutQuint); + // The outer gradient is resize with a slight delay from the border. // This is to give it a bomb-like effect, with the border "triggering" its animation when getting close. using (BeginDelayedSequence(flash_in_duration / 12)) From f3c92749bf280c10f5a9ed971bb92f55b7848b48 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Jan 2023 15:43:03 +0900 Subject: [PATCH 205/430] Fix code quality issues --- osu.Game/Skinning/LegacyJudgementPieceNew.cs | 5 +---- osu.Game/Skinning/LegacyJudgementPieceOld.cs | 2 +- osu.Game/Skinning/LegacySkin.cs | 4 ++-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/osu.Game/Skinning/LegacyJudgementPieceNew.cs b/osu.Game/Skinning/LegacyJudgementPieceNew.cs index 5e2bba9ccd..2f3a308b57 100644 --- a/osu.Game/Skinning/LegacyJudgementPieceNew.cs +++ b/osu.Game/Skinning/LegacyJudgementPieceNew.cs @@ -6,7 +6,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Textures; -using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; @@ -17,7 +16,6 @@ namespace osu.Game.Skinning public partial class LegacyJudgementPieceNew : CompositeDrawable, IAnimatableJudgement { private readonly HitResult result; - private readonly decimal? version; private readonly LegacyJudgementPieceOld? temporaryOldStyle; @@ -28,7 +26,6 @@ namespace osu.Game.Skinning public LegacyJudgementPieceNew(HitResult result, decimal? version, Func createMainDrawable, Texture? particleTexture) { this.result = result; - this.version = version; AutoSizeAxes = Axes.Both; Origin = Anchor.Centre; @@ -56,7 +53,7 @@ namespace osu.Game.Skinning if (result != HitResult.Miss) { //new judgement shows old as a temporary effect - AddInternal(temporaryOldStyle = new LegacyJudgementPieceOld(result, this.version, createMainDrawable, 1.05f, true) + AddInternal(temporaryOldStyle = new LegacyJudgementPieceOld(result, version, createMainDrawable, 1.05f, true) { Blending = BlendingParameters.Additive, Anchor = Anchor.Centre, diff --git a/osu.Game/Skinning/LegacyJudgementPieceOld.cs b/osu.Game/Skinning/LegacyJudgementPieceOld.cs index e427e19a6b..ed3a88219e 100644 --- a/osu.Game/Skinning/LegacyJudgementPieceOld.cs +++ b/osu.Game/Skinning/LegacyJudgementPieceOld.cs @@ -58,7 +58,7 @@ namespace osu.Game.Skinning this.ScaleTo(1.6f); this.ScaleTo(1, 100, Easing.In); - if (this.version > 1) + if (version > 1) { this.MoveTo(new Vector2(0, -5)); this.MoveToOffset(new Vector2(0, 80), fade_out_delay + fade_out_length, Easing.In); diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 0942966b1c..04bb551668 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -390,9 +390,9 @@ namespace osu.Game.Skinning var particle = getParticleTexture(resultComponent.Component); if (particle != null) - return new LegacyJudgementPieceNew(resultComponent.Component, this.Configuration.LegacyVersion, createDrawable, particle); + return new LegacyJudgementPieceNew(resultComponent.Component, Configuration.LegacyVersion, createDrawable, particle); - return new LegacyJudgementPieceOld(resultComponent.Component, this.Configuration.LegacyVersion, createDrawable); + return new LegacyJudgementPieceOld(resultComponent.Component, Configuration.LegacyVersion, createDrawable); } return null; From 7cd21e12f3278d8da8e8fc1378d20e0393a6cef5 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 26 Jan 2023 09:46:41 +0300 Subject: [PATCH 206/430] Implement masking property for TrianglesV2 background --- .../TestSceneTrianglesV2Background.cs | 58 +++++++++++++++++-- osu.Game/Graphics/Backgrounds/TrianglesV2.cs | 50 ++++++++++++---- 2 files changed, 90 insertions(+), 18 deletions(-) diff --git a/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs b/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs index ae1f3de6bf..01a2464b8e 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs @@ -8,12 +8,14 @@ using osuTK; using osuTK.Graphics; using osu.Game.Graphics.Backgrounds; using osu.Framework.Graphics.Colour; +using osu.Game.Graphics.Sprites; namespace osu.Game.Tests.Visual.Background { public partial class TestSceneTrianglesV2Background : OsuTestScene { private readonly TrianglesV2 triangles; + private readonly TrianglesV2 maskedTriangles; private readonly Box box; public TestSceneTrianglesV2Background() @@ -31,12 +33,20 @@ namespace osu.Game.Tests.Visual.Background Origin = Anchor.Centre, AutoSizeAxes = Axes.Both, Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 5), + Spacing = new Vector2(0, 10), Children = new Drawable[] { + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = "Masked" + }, new Container { Size = new Vector2(500, 100), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, Masking = true, CornerRadius = 40, Children = new Drawable[] @@ -54,9 +64,43 @@ namespace osu.Game.Tests.Visual.Background } } }, + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = "Non-masked" + }, new Container { Size = new Vector2(500, 100), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Red + }, + maskedTriangles = new TrianglesV2 + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both + } + } + }, + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = "Gradient comparison box" + }, + new Container + { + Size = new Vector2(500, 100), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, Masking = true, CornerRadius = 40, Child = box = new Box @@ -75,14 +119,16 @@ namespace osu.Game.Tests.Visual.Background AddSliderStep("Spawn ratio", 0f, 10f, 1f, s => { - triangles.SpawnRatio = s; + triangles.SpawnRatio = maskedTriangles.SpawnRatio = s; triangles.Reset(1234); + maskedTriangles.Reset(1234); }); - AddSliderStep("Thickness", 0f, 1f, 0.02f, t => triangles.Thickness = t); + AddSliderStep("Thickness", 0f, 1f, 0.02f, t => triangles.Thickness = maskedTriangles.Thickness = t); - AddStep("White colour", () => box.Colour = triangles.Colour = Color4.White); - AddStep("Vertical gradient", () => box.Colour = triangles.Colour = ColourInfo.GradientVertical(Color4.White, Color4.Red)); - AddStep("Horizontal gradient", () => box.Colour = triangles.Colour = ColourInfo.GradientHorizontal(Color4.White, Color4.Red)); + AddStep("White colour", () => box.Colour = triangles.Colour = maskedTriangles.Colour = Color4.White); + AddStep("Vertical gradient", () => box.Colour = triangles.Colour = maskedTriangles.Colour = ColourInfo.GradientVertical(Color4.White, Color4.Red)); + AddStep("Horizontal gradient", () => box.Colour = triangles.Colour = maskedTriangles.Colour = ColourInfo.GradientHorizontal(Color4.White, Color4.Red)); + AddToggleStep("Masking", m => maskedTriangles.Masking = m); } } } diff --git a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs index d543f082b4..3bc8bb6df1 100644 --- a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs +++ b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs @@ -34,6 +34,12 @@ namespace osu.Game.Graphics.Backgrounds /// protected virtual bool CreateNewTriangles => true; + /// + /// If enabled, only the portion of triangles that falls within this 's + /// shape is drawn to the screen. + /// + public bool Masking { get; set; } + private readonly BindableFloat spawnRatio = new BindableFloat(1f); /// @@ -189,6 +195,7 @@ namespace osu.Game.Graphics.Backgrounds private Vector2 size; private float thickness; private float texelSize; + private bool masking; private IVertexBatch? vertexBatch; @@ -205,6 +212,7 @@ namespace osu.Game.Graphics.Backgrounds texture = Source.texture; size = Source.DrawSize; thickness = Source.Thickness; + masking = Source.Masking; Quad triangleQuad = new Quad( Vector2Extensions.Transform(Vector2.Zero, DrawInfo.Matrix), @@ -236,26 +244,31 @@ namespace osu.Game.Graphics.Backgrounds shader.GetUniform("thickness").UpdateValue(ref thickness); shader.GetUniform("texelSize").UpdateValue(ref texelSize); - float relativeHeight = triangleSize.Y / size.Y; - float relativeWidth = triangleSize.X / size.X; + Vector2 relativeSize = Vector2.Divide(triangleSize, size); foreach (TriangleParticle particle in parts) { - Vector2 topLeft = particle.Position - new Vector2(relativeWidth * 0.5f, 0f); - Vector2 topRight = topLeft + new Vector2(relativeWidth, 0f); - Vector2 bottomLeft = topLeft + new Vector2(0f, relativeHeight); - Vector2 bottomRight = bottomLeft + new Vector2(relativeWidth, 0f); + Vector2 topLeft = particle.Position - new Vector2(relativeSize.X * 0.5f, 0f); + + Quad triangleQuad = masking ? clampToDrawable(topLeft, relativeSize) : new Quad(topLeft.X, topLeft.Y, relativeSize.X, relativeSize.Y); var drawQuad = new Quad( - Vector2Extensions.Transform(topLeft * size, DrawInfo.Matrix), - Vector2Extensions.Transform(topRight * size, DrawInfo.Matrix), - Vector2Extensions.Transform(bottomLeft * size, DrawInfo.Matrix), - Vector2Extensions.Transform(bottomRight * size, DrawInfo.Matrix) + Vector2Extensions.Transform(triangleQuad.TopLeft * size, DrawInfo.Matrix), + Vector2Extensions.Transform(triangleQuad.TopRight * size, DrawInfo.Matrix), + Vector2Extensions.Transform(triangleQuad.BottomLeft * size, DrawInfo.Matrix), + Vector2Extensions.Transform(triangleQuad.BottomRight * size, DrawInfo.Matrix) ); - ColourInfo colourInfo = triangleColourInfo(DrawColourInfo.Colour, new Quad(topLeft, topRight, bottomLeft, bottomRight)); + ColourInfo colourInfo = triangleColourInfo(DrawColourInfo.Colour, triangleQuad); - renderer.DrawQuad(texture, drawQuad, colourInfo, vertexAction: vertexBatch.AddAction); + RectangleF textureCoords = new RectangleF( + triangleQuad.TopLeft.X - topLeft.X, + triangleQuad.TopLeft.Y - topLeft.Y, + triangleQuad.Width, + triangleQuad.Height + ) / relativeSize; + + renderer.DrawQuad(texture, drawQuad, colourInfo, new RectangleF(0, 0, 1, 1), vertexBatch.AddAction, textureCoords: textureCoords); } shader.Unbind(); @@ -272,6 +285,19 @@ namespace osu.Game.Graphics.Backgrounds }; } + private static Quad clampToDrawable(Vector2 topLeft, Vector2 size) + { + float leftClamped = Math.Clamp(topLeft.X, 0f, 1f); + float topClamped = Math.Clamp(topLeft.Y, 0f, 1f); + + return new Quad( + leftClamped, + topClamped, + Math.Clamp(topLeft.X + size.X, 0f, 1f) - leftClamped, + Math.Clamp(topLeft.Y + size.Y, 0f, 1f) - topClamped + ); + } + protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); From d63719a602b3c5ef397d6cf6017cfc31a34a1476 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Jan 2023 16:04:56 +0900 Subject: [PATCH 207/430] Move and rename the base component class --- osu.Game/Skinning/Components/BeatmapAttributeText.cs | 2 +- osu.Game/Skinning/Components/TextElement.cs | 2 +- ...ultTextSkinComponent.cs => FontAdjustableSkinComponent.cs} | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename osu.Game/Skinning/{Components/DefaultTextSkinComponent.cs => FontAdjustableSkinComponent.cs} (88%) diff --git a/osu.Game/Skinning/Components/BeatmapAttributeText.cs b/osu.Game/Skinning/Components/BeatmapAttributeText.cs index 5696158d49..68bb1e7ddc 100644 --- a/osu.Game/Skinning/Components/BeatmapAttributeText.cs +++ b/osu.Game/Skinning/Components/BeatmapAttributeText.cs @@ -23,7 +23,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Skinning.Components { [UsedImplicitly] - public partial class BeatmapAttributeText : DefaultTextSkinComponent + public partial class BeatmapAttributeText : FontAdjustableSkinComponent { [SettingSource("Attribute", "The attribute to be displayed.")] public Bindable Attribute { get; } = new Bindable(BeatmapAttribute.StarRating); diff --git a/osu.Game/Skinning/Components/TextElement.cs b/osu.Game/Skinning/Components/TextElement.cs index fb779fdb83..d87fb125bb 100644 --- a/osu.Game/Skinning/Components/TextElement.cs +++ b/osu.Game/Skinning/Components/TextElement.cs @@ -12,7 +12,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Skinning.Components { [UsedImplicitly] - public partial class TextElement : DefaultTextSkinComponent + public partial class TextElement : FontAdjustableSkinComponent { [SettingSource("Text", "The text to be displayed.")] public Bindable Text { get; } = new Bindable("Circles!"); diff --git a/osu.Game/Skinning/Components/DefaultTextSkinComponent.cs b/osu.Game/Skinning/FontAdjustableSkinComponent.cs similarity index 88% rename from osu.Game/Skinning/Components/DefaultTextSkinComponent.cs rename to osu.Game/Skinning/FontAdjustableSkinComponent.cs index abe16918c5..716b472ba5 100644 --- a/osu.Game/Skinning/Components/DefaultTextSkinComponent.cs +++ b/osu.Game/Skinning/FontAdjustableSkinComponent.cs @@ -7,12 +7,12 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Configuration; using osu.Game.Graphics; -namespace osu.Game.Skinning.Components +namespace osu.Game.Skinning { /// /// Skin element that contains text and have ability to control its font. /// - public abstract partial class DefaultTextSkinComponent : Container, ISkinnableDrawable + public abstract partial class FontAdjustableSkinComponent : Container, ISkinnableDrawable { public bool UsesFixedAnchor { get; set; } From 64e7f6f138a5ae087f785b736248aba009b6bfe7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Jan 2023 16:05:07 +0900 Subject: [PATCH 208/430] Add more documentation around the implementation of `FontAdjustableSkinComponent` --- osu.Game/Skinning/FontAdjustableSkinComponent.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/osu.Game/Skinning/FontAdjustableSkinComponent.cs b/osu.Game/Skinning/FontAdjustableSkinComponent.cs index 716b472ba5..ee73417bfe 100644 --- a/osu.Game/Skinning/FontAdjustableSkinComponent.cs +++ b/osu.Game/Skinning/FontAdjustableSkinComponent.cs @@ -10,23 +10,30 @@ using osu.Game.Graphics; namespace osu.Game.Skinning { /// - /// Skin element that contains text and have ability to control its font. + /// A skin component that contains text and allows the user to choose its font. /// public abstract partial class FontAdjustableSkinComponent : Container, ISkinnableDrawable { public bool UsesFixedAnchor { get; set; } - [SettingSource("Font", "Font to use.")] + [SettingSource("Font", "The font to use.")] public Bindable Font { get; } = new Bindable(Typeface.Torus); + /// + /// Implement to apply the user font selection to one or more components. + /// protected abstract void SetFont(FontUsage font); protected override void LoadComplete() { base.LoadComplete(); + Font.BindValueChanged(e => { - FontUsage f = OsuFont.GetFont(e.NewValue, weight: e.NewValue == Typeface.Venera ? FontWeight.Bold : FontWeight.Regular); + // We only have bold weight for venera, so let's force that. + FontWeight fontWeight = e.NewValue == Typeface.Venera ? FontWeight.Bold : FontWeight.Regular; + + FontUsage f = OsuFont.GetFont(e.NewValue, weight: fontWeight); SetFont(f); }, true); } From e5d4979bc3942aa564a758bf5e09331dcc3ebdcb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Jan 2023 16:56:37 +0900 Subject: [PATCH 209/430] Fix default health bar having a very weird anchor point in the skin editor --- .../Screens/Play/HUD/DefaultHealthDisplay.cs | 45 +++++++++++-------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/DefaultHealthDisplay.cs b/osu.Game/Screens/Play/HUD/DefaultHealthDisplay.cs index 76027f9e5d..62d66efb33 100644 --- a/osu.Game/Screens/Play/HUD/DefaultHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/DefaultHealthDisplay.cs @@ -78,30 +78,39 @@ namespace osu.Game.Screens.Play.HUD public DefaultHealthDisplay() { - Size = new Vector2(1, 5); - RelativeSizeAxes = Axes.X; - Margin = new MarginPadding { Top = 20 }; + const float padding = 20; + const float bar_height = 5; - InternalChildren = new Drawable[] + Size = new Vector2(1, bar_height + padding * 2); + RelativeSizeAxes = Axes.X; + + InternalChild = new Container { - new Box + Padding = new MarginPadding { Vertical = padding }, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - }, - fill = new Container - { - RelativeSizeAxes = Axes.Both, - Size = new Vector2(0, 1), - Masking = true, - Children = new[] + new Box { - new Box + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + }, + fill = new Container + { + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0, 1), + Masking = true, + Children = new[] { - RelativeSizeAxes = Axes.Both, + new Box + { + RelativeSizeAxes = Axes.Both, + } } - } - }, + }, + } }; } From 7344d34d5b59ef6c9517478df3903482a77ad106 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Jan 2023 17:12:41 +0900 Subject: [PATCH 210/430] Move `where` class specs to next line --- .../Blueprints/Sliders/Components/PathControlPointPiece.cs | 3 ++- .../Sliders/Components/PathControlPointVisualiser.cs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs index a4d5c08b8a..12e5ca0236 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs @@ -32,7 +32,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components /// A visualisation of a single in an osu hit object with a path. /// /// The type of which this visualises. - public partial class PathControlPointPiece : BlueprintPiece, IHasTooltip where T : OsuHitObject, IHasPath + public partial class PathControlPointPiece : BlueprintPiece, IHasTooltip + where T : OsuHitObject, IHasPath { public Action, MouseButtonEvent> RequestSelection; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index 0310239052..17d0fc457a 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -29,7 +29,8 @@ using osuTK.Input; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { - public partial class PathControlPointVisualiser : CompositeDrawable, IKeyBindingHandler, IHasContextMenu where T : OsuHitObject, IHasPath + public partial class PathControlPointVisualiser : CompositeDrawable, IKeyBindingHandler, IHasContextMenu + where T : OsuHitObject, IHasPath { public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; // allow context menu to appear outside of the playfield. From 2017ac11358c489eeda992c176e30acdbfeeca33 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Jan 2023 17:46:19 +0900 Subject: [PATCH 211/430] Apply NRT to all skin editor classes --- osu.Game/Skinning/Editor/SkinBlueprint.cs | 10 ++-- .../Skinning/Editor/SkinBlueprintContainer.cs | 6 +-- osu.Game/Skinning/Editor/SkinEditor.cs | 54 +++++++++++-------- osu.Game/Skinning/Editor/SkinEditorOverlay.cs | 22 ++++---- .../Skinning/Editor/SkinEditorSceneLibrary.cs | 20 +++---- .../Skinning/Editor/SkinSelectionHandler.cs | 4 +- 6 files changed, 59 insertions(+), 57 deletions(-) diff --git a/osu.Game/Skinning/Editor/SkinBlueprint.cs b/osu.Game/Skinning/Editor/SkinBlueprint.cs index fc7e9e8ef1..c5e822a17a 100644 --- a/osu.Game/Skinning/Editor/SkinBlueprint.cs +++ b/osu.Game/Skinning/Editor/SkinBlueprint.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.Extensions.Color4Extensions; @@ -20,18 +18,18 @@ namespace osu.Game.Skinning.Editor { public partial class SkinBlueprint : SelectionBlueprint { - private Container box; + private Container box = null!; - private Container outlineBox; + private Container outlineBox = null!; - private AnchorOriginVisualiser anchorOriginVisualiser; + private AnchorOriginVisualiser anchorOriginVisualiser = null!; private Drawable drawable => (Drawable)Item; protected override bool ShouldBeAlive => drawable.IsAlive && Item.IsPresent; [Resolved] - private OsuColour colours { get; set; } + private OsuColour colours { get; set; } = null!; public SkinBlueprint(ISkinnableDrawable component) : base(component) diff --git a/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs b/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs index 9812406aad..2998136aca 100644 --- a/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs +++ b/osu.Game/Skinning/Editor/SkinBlueprintContainer.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.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics; @@ -28,7 +26,7 @@ namespace osu.Game.Skinning.Editor private readonly List> targetComponents = new List>(); [Resolved] - private SkinEditor editor { get; set; } + private SkinEditor editor { get; set; } = null!; public SkinBlueprintContainer(Drawable target) { @@ -61,7 +59,7 @@ namespace osu.Game.Skinning.Editor } } - private void componentsChanged(object sender, NotifyCollectionChangedEventArgs e) => Schedule(() => + private void componentsChanged(object? sender, NotifyCollectionChangedEventArgs e) => Schedule(() => { switch (e.Action) { diff --git a/osu.Game/Skinning/Editor/SkinEditor.cs b/osu.Game/Skinning/Editor/SkinEditor.cs index 98b4e960dd..5c0c8b2427 100644 --- a/osu.Game/Skinning/Editor/SkinEditor.cs +++ b/osu.Game/Skinning/Editor/SkinEditor.cs @@ -1,10 +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.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Threading.Tasks; @@ -42,39 +41,39 @@ namespace osu.Game.Skinning.Editor protected override bool StartHidden => true; - private Drawable targetScreen; + private Drawable targetScreen = null!; - private OsuTextFlowContainer headerText; + private OsuTextFlowContainer headerText = null!; - private Bindable currentSkin; - - [Resolved(canBeNull: true)] - private OsuGame game { get; set; } + private Bindable currentSkin = null!; [Resolved] - private SkinManager skins { get; set; } + private OsuGame? game { get; set; } [Resolved] - private OsuColour colours { get; set; } + private SkinManager skins { get; set; } = null!; [Resolved] - private RealmAccess realm { get; set; } + private OsuColour colours { get; set; } = null!; - [Resolved(canBeNull: true)] - private SkinEditorOverlay skinEditorOverlay { get; set; } + [Resolved] + private RealmAccess realm { get; set; } = null!; + + [Resolved] + private SkinEditorOverlay? skinEditorOverlay { get; set; } [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); private bool hasBegunMutating; - private Container content; + private Container? content; - private EditorSidebar componentsSidebar; - private EditorSidebar settingsSidebar; + private EditorSidebar componentsSidebar = null!; + private EditorSidebar settingsSidebar = null!; - [Resolved(canBeNull: true)] - private OnScreenDisplay onScreenDisplay { get; set; } + [Resolved] + private OnScreenDisplay? onScreenDisplay { get; set; } public SkinEditor() { @@ -234,11 +233,14 @@ namespace osu.Game.Skinning.Editor // Immediately clear the previous blueprint container to ensure it doesn't try to interact with the old target. content?.Clear(); + Scheduler.AddOnce(loadBlueprintContainer); Scheduler.AddOnce(populateSettings); void loadBlueprintContainer() { + Debug.Assert(content != null); + content.Child = new SkinBlueprintContainer(targetScreen); componentsSidebar.Child = new SkinComponentToolbox(getFirstTarget() as CompositeDrawable) @@ -311,9 +313,9 @@ namespace osu.Game.Skinning.Editor private IEnumerable availableTargets => targetScreen.ChildrenOfType(); - private ISkinnableTarget getFirstTarget() => availableTargets.FirstOrDefault(); + private ISkinnableTarget? getFirstTarget() => availableTargets.FirstOrDefault(); - private ISkinnableTarget getTarget(GlobalSkinComponentLookup.LookupType target) + private ISkinnableTarget? getTarget(GlobalSkinComponentLookup.LookupType target) { return availableTargets.FirstOrDefault(c => c.Target == target); } @@ -327,7 +329,7 @@ namespace osu.Game.Skinning.Editor currentSkin.Value.ResetDrawableTarget(t); // add back default components - getTarget(t.Target).Reload(); + getTarget(t.Target)?.Reload(); } } @@ -342,7 +344,7 @@ namespace osu.Game.Skinning.Editor currentSkin.Value.UpdateDrawableTarget(t); skins.Save(skins.CurrentSkin.Value); - onScreenDisplay?.Display(new SkinEditorToast(ToastStrings.SkinSaved, currentSkin.Value.SkinInfo.ToString())); + onScreenDisplay?.Display(new SkinEditorToast(ToastStrings.SkinSaved, currentSkin.Value.SkinInfo.ToString() ?? "Unknown")); } protected override bool OnHover(HoverEvent e) => true; @@ -394,12 +396,18 @@ namespace osu.Game.Skinning.Editor // This is the best we can do for now. realm.Run(r => r.Refresh()); + var skinnableTarget = getFirstTarget(); + + // Import still should happen for now, even if not placeable (as it allows a user to import skin resources that would apply to legacy gameplay skins). + if (skinnableTarget == null) + return; + // place component var sprite = new SkinnableSprite { SpriteName = { Value = file.Name }, Origin = Anchor.Centre, - Position = getFirstTarget().ToLocalSpace(GetContainingInputManager().CurrentState.Mouse.Position), + Position = skinnableTarget.ToLocalSpace(GetContainingInputManager().CurrentState.Mouse.Position), }; placeComponent(sprite, false); diff --git a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs index 35e28ee665..f15afc7feb 100644 --- a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs +++ b/osu.Game/Skinning/Editor/SkinEditorOverlay.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.Diagnostics; -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -29,13 +26,12 @@ namespace osu.Game.Skinning.Editor protected override bool BlockNonPositionalInput => true; - [CanBeNull] - private SkinEditor skinEditor; + private SkinEditor? skinEditor; - [Resolved(canBeNull: true)] - private OsuGame game { get; set; } + [Resolved] + private OsuGame game { get; set; } = null!; - private OsuScreen lastTargetScreen; + private OsuScreen? lastTargetScreen; private Vector2 lastDrawSize; @@ -81,6 +77,8 @@ namespace osu.Game.Skinning.Editor AddInternal(editor); + Debug.Assert(lastTargetScreen != null); + SetTarget(lastTargetScreen); }); } @@ -124,15 +122,15 @@ namespace osu.Game.Skinning.Editor { Scheduler.AddOnce(updateScreenSizing); - game?.Toolbar.Hide(); - game?.CloseAllOverlays(); + game.Toolbar.Hide(); + game.CloseAllOverlays(); } else { scalingContainer.SetCustomRect(null); if (lastTargetScreen?.HideOverlaysOnEnter != true) - game?.Toolbar.Show(); + game.Toolbar.Show(); } } @@ -158,7 +156,7 @@ namespace osu.Game.Skinning.Editor Scheduler.AddOnce(setTarget, screen); } - private void setTarget(OsuScreen target) + private void setTarget(OsuScreen? target) { if (target == null) return; diff --git a/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs b/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs index 44045e8916..c2c7961aac 100644 --- a/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs +++ b/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs @@ -1,11 +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.Collections.Generic; using System.Linq; -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -36,14 +33,14 @@ namespace osu.Game.Skinning.Editor private const float padding = 10; - [Resolved(canBeNull: true)] - private IPerformFromScreenRunner performer { get; set; } + [Resolved] + private IPerformFromScreenRunner? performer { get; set; } [Resolved] - private IBindable ruleset { get; set; } + private IBindable ruleset { get; set; } = null!; [Resolved] - private Bindable> mods { get; set; } + private Bindable> mods { get; set; } = null!; public SkinEditorSceneLibrary() { @@ -107,7 +104,12 @@ namespace osu.Game.Skinning.Editor var replayGeneratingMod = ruleset.Value.CreateInstance().GetAutoplayMod(); - if (!ModUtils.CheckCompatibleSet(mods.Value.Append(replayGeneratingMod), out var invalid)) + IReadOnlyList usableMods = mods.Value; + + if (replayGeneratingMod != null) + usableMods = usableMods.Append(replayGeneratingMod).ToArray(); + + if (!ModUtils.CheckCompatibleSet(usableMods, out var invalid)) mods.Value = mods.Value.Except(invalid).ToArray(); if (replayGeneratingMod != null) @@ -130,7 +132,7 @@ namespace osu.Game.Skinning.Editor } [BackgroundDependencyLoader(true)] - private void load([CanBeNull] OverlayColourProvider overlayColourProvider, OsuColour colours) + private void load(OverlayColourProvider? overlayColourProvider, OsuColour colours) { BackgroundColour = overlayColourProvider?.Background3 ?? colours.Blue3; Content.CornerRadius = 5; diff --git a/osu.Game/Skinning/Editor/SkinSelectionHandler.cs b/osu.Game/Skinning/Editor/SkinSelectionHandler.cs index 2c3f6238ec..d67cbef481 100644 --- a/osu.Game/Skinning/Editor/SkinSelectionHandler.cs +++ b/osu.Game/Skinning/Editor/SkinSelectionHandler.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; @@ -23,7 +21,7 @@ namespace osu.Game.Skinning.Editor public partial class SkinSelectionHandler : SelectionHandler { [Resolved] - private SkinEditor skinEditor { get; set; } + private SkinEditor skinEditor { get; set; } = null!; public override bool HandleRotation(float angle) { From 4352c56c3e4d8ea884d3872069be93a3795a443f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Jan 2023 17:52:49 +0900 Subject: [PATCH 212/430] Apply NRT to all simple auxiliary skin classes --- osu.Game/Skinning/Components/BigBlackBox.cs | 2 -- osu.Game/Skinning/LegacyRollingCounter.cs | 2 -- osu.Game/Skinning/LegacyScoreCounter.cs | 2 -- osu.Game/Skinning/LegacySkinDecoder.cs | 2 -- osu.Game/Skinning/LegacySpriteText.cs | 8 +++----- osu.Game/Skinning/SkinCustomColourLookup.cs | 2 -- osu.Game/Skinning/SkinnableSound.cs | 14 +++++--------- 7 files changed, 8 insertions(+), 24 deletions(-) diff --git a/osu.Game/Skinning/Components/BigBlackBox.cs b/osu.Game/Skinning/Components/BigBlackBox.cs index 4210a70b72..043a276e49 100644 --- a/osu.Game/Skinning/Components/BigBlackBox.cs +++ b/osu.Game/Skinning/Components/BigBlackBox.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 JetBrains.Annotations; using osu.Framework.Bindables; using osu.Framework.Graphics; diff --git a/osu.Game/Skinning/LegacyRollingCounter.cs b/osu.Game/Skinning/LegacyRollingCounter.cs index 465f1c3a20..8282b2f88b 100644 --- a/osu.Game/Skinning/LegacyRollingCounter.cs +++ b/osu.Game/Skinning/LegacyRollingCounter.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.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; diff --git a/osu.Game/Skinning/LegacyScoreCounter.cs b/osu.Game/Skinning/LegacyScoreCounter.cs index 6a14ed93e9..88e7bbc23a 100644 --- a/osu.Game/Skinning/LegacyScoreCounter.cs +++ b/osu.Game/Skinning/LegacyScoreCounter.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.Game.Graphics.Sprites; using osu.Game.Screens.Play.HUD; diff --git a/osu.Game/Skinning/LegacySkinDecoder.cs b/osu.Game/Skinning/LegacySkinDecoder.cs index 11c21d432f..1270f69339 100644 --- a/osu.Game/Skinning/LegacySkinDecoder.cs +++ b/osu.Game/Skinning/LegacySkinDecoder.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.Globalization; using osu.Game.Beatmaps.Formats; diff --git a/osu.Game/Skinning/LegacySpriteText.cs b/osu.Game/Skinning/LegacySpriteText.cs index b89f85778b..d6af52855b 100644 --- a/osu.Game/Skinning/LegacySpriteText.cs +++ b/osu.Game/Skinning/LegacySpriteText.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.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Graphics.Sprites; @@ -16,7 +14,7 @@ namespace osu.Game.Skinning { private readonly LegacyFont font; - private LegacyGlyphStore glyphStore; + private LegacyGlyphStore glyphStore = null!; protected override char FixedWidthReferenceCharacter => '5'; @@ -49,7 +47,7 @@ namespace osu.Game.Skinning this.skin = skin; } - public ITexturedCharacterGlyph Get(string fontName, char character) + public ITexturedCharacterGlyph? Get(string fontName, char character) { string lookup = getLookupName(character); @@ -79,7 +77,7 @@ namespace osu.Game.Skinning } } - public Task GetAsync(string fontName, char character) => Task.Run(() => Get(fontName, character)); + public Task GetAsync(string fontName, char character) => Task.Run(() => Get(fontName, character)); } } } diff --git a/osu.Game/Skinning/SkinCustomColourLookup.cs b/osu.Game/Skinning/SkinCustomColourLookup.cs index 319b071bf5..b8e5ac9b53 100644 --- a/osu.Game/Skinning/SkinCustomColourLookup.cs +++ b/osu.Game/Skinning/SkinCustomColourLookup.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.Skinning { public class SkinCustomColourLookup diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs index aeced9b517..ec296d4e89 100644 --- a/osu.Game/Skinning/SkinnableSound.cs +++ b/osu.Game/Skinning/SkinnableSound.cs @@ -1,12 +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.Collections.Generic; using System.Linq; -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Bindables; @@ -39,13 +36,12 @@ namespace osu.Game.Skinning /// /// All raw s contained in this . /// - [NotNull, ItemNotNull] protected IEnumerable DrawableSamples => samplesContainer.Select(c => c.Sample).Where(s => s != null); private readonly AudioContainer samplesContainer; - [Resolved(CanBeNull = true)] - private IPooledSampleProvider samplePool { get; set; } + [Resolved] + private IPooledSampleProvider? samplePool { get; set; } /// /// Creates a new . @@ -59,7 +55,7 @@ namespace osu.Game.Skinning /// Creates a new with some initial samples. /// /// The initial samples. - public SkinnableSound([NotNull] IEnumerable samples) + public SkinnableSound(IEnumerable samples) : this() { this.samples = samples.ToArray(); @@ -69,7 +65,7 @@ namespace osu.Game.Skinning /// Creates a new with an initial sample. /// /// The initial sample. - public SkinnableSound([NotNull] ISampleInfo sample) + public SkinnableSound(ISampleInfo sample) : this(new[] { sample }) { } @@ -79,7 +75,7 @@ namespace osu.Game.Skinning /// /// The samples that should be played. /// - public ISampleInfo[] Samples + public ISampleInfo[]? Samples { get => samples; set From 398813147548513d6ceb47ea74f813dfed2adea9 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 26 Jan 2023 12:12:56 +0100 Subject: [PATCH 213/430] 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 214/430] 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 215/430] 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 216/430] 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 217/430] 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 758b4c8cfcc7b1ecbb91e64ea8230d211bd6de8f Mon Sep 17 00:00:00 2001 From: EXtremeExploit Date: Thu, 26 Jan 2023 10:01:33 -0300 Subject: [PATCH 218/430] Do the thing aka fix the if --- osu.Game/Skinning/LegacyJudgementPieceNew.cs | 4 ++-- osu.Game/Skinning/LegacyJudgementPieceOld.cs | 12 ++++++++---- osu.Game/Skinning/LegacySkin.cs | 4 ++-- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/osu.Game/Skinning/LegacyJudgementPieceNew.cs b/osu.Game/Skinning/LegacyJudgementPieceNew.cs index 2f3a308b57..9b1ff9b22f 100644 --- a/osu.Game/Skinning/LegacyJudgementPieceNew.cs +++ b/osu.Game/Skinning/LegacyJudgementPieceNew.cs @@ -23,7 +23,7 @@ namespace osu.Game.Skinning private readonly ParticleExplosion? particles; - public LegacyJudgementPieceNew(HitResult result, decimal? version, Func createMainDrawable, Texture? particleTexture) + public LegacyJudgementPieceNew(HitResult result, Func createMainDrawable, Texture? particleTexture) { this.result = result; @@ -53,7 +53,7 @@ namespace osu.Game.Skinning if (result != HitResult.Miss) { //new judgement shows old as a temporary effect - AddInternal(temporaryOldStyle = new LegacyJudgementPieceOld(result, version, createMainDrawable, 1.05f, true) + AddInternal(temporaryOldStyle = new LegacyJudgementPieceOld(result, createMainDrawable, 1.05f, true) { Blending = BlendingParameters.Additive, Anchor = Anchor.Centre, diff --git a/osu.Game/Skinning/LegacyJudgementPieceOld.cs b/osu.Game/Skinning/LegacyJudgementPieceOld.cs index ed3a88219e..69d38b06c5 100644 --- a/osu.Game/Skinning/LegacyJudgementPieceOld.cs +++ b/osu.Game/Skinning/LegacyJudgementPieceOld.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; using osu.Framework.Graphics.Containers; @@ -17,15 +18,16 @@ namespace osu.Game.Skinning public partial class LegacyJudgementPieceOld : CompositeDrawable, IAnimatableJudgement { private readonly HitResult result; - private readonly decimal? version; private readonly float finalScale; private readonly bool forceTransforms; - public LegacyJudgementPieceOld(HitResult result, decimal? version, Func createMainDrawable, float finalScale = 1f, bool forceTransforms = false) + [Resolved] + private ISkinSource skin { get; set; } = null!; + + public LegacyJudgementPieceOld(HitResult result, Func createMainDrawable, float finalScale = 1f, bool forceTransforms = false) { this.result = result; - this.version = version; this.finalScale = finalScale; this.forceTransforms = forceTransforms; @@ -58,7 +60,9 @@ namespace osu.Game.Skinning this.ScaleTo(1.6f); this.ScaleTo(1, 100, Easing.In); - if (version > 1) + decimal? legacyVersion = skin.GetConfig(SkinConfiguration.LegacySetting.Version)?.Value; + + if (legacyVersion > 1) { this.MoveTo(new Vector2(0, -5)); this.MoveToOffset(new Vector2(0, 80), fade_out_delay + fade_out_length, Easing.In); diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 04bb551668..5f12d2ce23 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -390,9 +390,9 @@ namespace osu.Game.Skinning var particle = getParticleTexture(resultComponent.Component); if (particle != null) - return new LegacyJudgementPieceNew(resultComponent.Component, Configuration.LegacyVersion, createDrawable, particle); + return new LegacyJudgementPieceNew(resultComponent.Component, createDrawable, particle); - return new LegacyJudgementPieceOld(resultComponent.Component, Configuration.LegacyVersion, createDrawable); + return new LegacyJudgementPieceOld(resultComponent.Component, createDrawable); } return null; From 374c3b56f6f2e8b74fd87c538baa5354bf59d708 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 26 Jan 2023 13:21:20 +0100 Subject: [PATCH 219/430] 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 220/430] 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 221/430] 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 222/430] 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 223/430] 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 224/430] 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 225/430] 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 226/430] 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 227/430] 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 228/430] 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 2b55e05b10857a09c3162fec5ef965da3034e775 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 27 Jan 2023 13:31:21 +0900 Subject: [PATCH 229/430] Adjust argon hit lighting further --- .../Skinning/Argon/ArgonMainCirclePiece.cs | 41 ++++++++++--------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs index 2a53122cc1..9e86e1e411 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs @@ -151,10 +151,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon const float shrink_size = 0.8f; - // When the user has hit lighting disabled, we won't be showing the bright white flash. - // To make things look good, the surrounding animations are also slightly adjusted. - bool showFlash = configHitLighting.Value; - // Animating with the number present is distracting. // The number disappearing is hidden by the bright flash. number.FadeOut(flash_in_duration / 2); @@ -186,25 +182,28 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon { outerGradient.ResizeTo(OUTER_GRADIENT_SIZE * shrink_size, resize_duration, Easing.OutElasticHalf); - if (showFlash) - { - outerGradient - .FadeColour(Color4.White, 80) - .Then() - .FadeOut(flash_in_duration); - } - else - { - outerGradient - .FadeColour(Color4.White, flash_in_duration * 8) - .FadeOut(flash_in_duration * 2); - } + outerGradient + .FadeColour(Color4.White, 80) + .Then() + .FadeOut(flash_in_duration); } - if (showFlash) + if (configHitLighting.Value) + { + flash.HitLighting = true; flash.FadeTo(1, flash_in_duration, Easing.OutQuint); - this.FadeOut(showFlash ? fade_out_time : fade_out_time / 2, Easing.OutQuad); + this.FadeOut(fade_out_time, Easing.OutQuad); + } + else + { + flash.HitLighting = false; + flash.FadeTo(1, flash_in_duration, Easing.OutQuint) + .Then() + .FadeOut(flash_in_duration, Easing.OutQuint); + + this.FadeOut(fade_out_time * 0.8f, Easing.OutQuad); + } break; } @@ -236,6 +235,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon Child.AlwaysPresent = true; } + public bool HitLighting { get; set; } + protected override void Update() { base.Update(); @@ -244,7 +245,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon { Type = EdgeEffectType.Glow, Colour = Colour, - Radius = OsuHitObject.OBJECT_RADIUS * 1.2f, + Radius = OsuHitObject.OBJECT_RADIUS * (HitLighting ? 1.2f : 0.6f), }; } } From 8a9a6c733c839fdff3dd24d114c6494b7a335c47 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 27 Jan 2023 13:55:34 +0900 Subject: [PATCH 230/430] Apply missed cleanup to `BackgroundDependencyLoader` call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs b/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs index c2c7961aac..0936be3ee8 100644 --- a/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs +++ b/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs @@ -131,7 +131,7 @@ namespace osu.Game.Skinning.Editor Height = BUTTON_HEIGHT; } - [BackgroundDependencyLoader(true)] + [BackgroundDependencyLoader] private void load(OverlayColourProvider? overlayColourProvider, OsuColour colours) { BackgroundColour = overlayColourProvider?.Background3 ?? colours.Blue3; From 74ab036f3e695e640f531d8a86ba885c89c24f69 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 27 Jan 2023 19:32:30 +0900 Subject: [PATCH 231/430] Refactor `SkinnableSound.Samples` to be non-nullable --- .../Objects/Drawables/DrawableHoldNote.cs | 2 +- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs | 2 +- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs | 2 +- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 3 +-- osu.Game/Skinning/SkinnableSound.cs | 6 +++--- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs index 759d2346e8..264a1bd5ec 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs @@ -376,7 +376,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables protected override void OnFree() { - slidingSample.Samples = null; + slidingSample.ClearSamples(); base.OnFree(); } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 4601af45d8..a7b02596d5 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -126,7 +126,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables PathVersion.UnbindFrom(HitObject.Path.Version); - slidingSample.Samples = null; + slidingSample?.ClearSamples(); } protected override void LoadSamples() diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index eed5c3e2e3..a5193f1b6e 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -119,7 +119,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { base.OnFree(); - spinningSample.Samples = null; + spinningSample.ClearSamples(); } protected override void LoadSamples() diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index be5a7f71e7..39f0888882 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -303,8 +303,7 @@ namespace osu.Game.Rulesets.Objects.Drawables samplesBindable.CollectionChanged -= onSamplesChanged; // Release the samples for other hitobjects to use. - if (Samples != null) - Samples.Samples = null; + Samples?.ClearSamples(); foreach (var obj in nestedHitObjects) { diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs index ec296d4e89..475b79053a 100644 --- a/osu.Game/Skinning/SkinnableSound.cs +++ b/osu.Game/Skinning/SkinnableSound.cs @@ -75,13 +75,11 @@ namespace osu.Game.Skinning /// /// The samples that should be played. /// - public ISampleInfo[]? Samples + public ISampleInfo[] Samples { get => samples; set { - value ??= Array.Empty(); - if (samples == value) return; @@ -92,6 +90,8 @@ namespace osu.Game.Skinning } } + public void ClearSamples() => Samples = Array.Empty(); + private bool looping; /// From a126c72a4fbf150c59fba9e65bafe77ff02c5ad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 28 Jan 2023 15:17:35 +0100 Subject: [PATCH 232/430] Adjust skin resources test to facilitate loading many --- .../Skins/TestSceneSkinResources.cs | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Skins/TestSceneSkinResources.cs b/osu.Game.Tests/Skins/TestSceneSkinResources.cs index 748668b6ca..b29211f442 100644 --- a/osu.Game.Tests/Skins/TestSceneSkinResources.cs +++ b/osu.Game.Tests/Skins/TestSceneSkinResources.cs @@ -31,17 +31,14 @@ namespace osu.Game.Tests.Skins [Resolved] private SkinManager skins { get; set; } = null!; - private ISkin skin = null!; - - [BackgroundDependencyLoader] - private void load() - { - var imported = skins.Import(new ImportTask(TestResources.OpenResource("Archives/ogg-skin.osk"), "ogg-skin.osk")).GetResultSafely(); - skin = imported.PerformRead(skinInfo => skins.GetSkin(skinInfo)); - } - [Test] - public void TestRetrieveOggSample() => AddAssert("sample is non-null", () => skin.GetSample(new SampleInfo("sample")) != null); + public void TestRetrieveOggSample() + { + ISkin skin = null!; + + AddStep("import skin", () => skin = importSkinFromArchives(@"ogg-skin.osk")); + AddAssert("sample is non-null", () => skin.GetSample(new SampleInfo(@"sample")) != null); + } [Test] public void TestSampleRetrievalOrder() @@ -78,6 +75,12 @@ namespace osu.Game.Tests.Skins }); } + private Skin importSkinFromArchives(string filename) + { + var imported = skins.Import(new ImportTask(TestResources.OpenResource($@"Archives/{filename}"), filename)).GetResultSafely(); + return imported.PerformRead(skinInfo => skins.GetSkin(skinInfo)); + } + private class TestSkin : Skin { public const string SAMPLE_NAME = "test-sample"; From 9bdb78791f0bab12c70c7f3ef6159a6720b33338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 28 Jan 2023 15:23:15 +0100 Subject: [PATCH 233/430] Add failing test case --- .../Archives/conflicting-filenames-skin.osk | Bin 0 -> 3665 bytes osu.Game.Tests/Skins/TestSceneSkinResources.cs | 10 ++++++++++ 2 files changed, 10 insertions(+) create mode 100644 osu.Game.Tests/Resources/Archives/conflicting-filenames-skin.osk diff --git a/osu.Game.Tests/Resources/Archives/conflicting-filenames-skin.osk b/osu.Game.Tests/Resources/Archives/conflicting-filenames-skin.osk new file mode 100644 index 0000000000000000000000000000000000000000..73576f3e22dd29c4c6a99ca62cf5e842f1760f33 GIT binary patch literal 3665 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 Q^%a4Fbl;F-BK_6tU*i>nr2qf` literal 0 HcmV?d00001 diff --git a/osu.Game.Tests/Skins/TestSceneSkinResources.cs b/osu.Game.Tests/Skins/TestSceneSkinResources.cs index b29211f442..aaec319b57 100644 --- a/osu.Game.Tests/Skins/TestSceneSkinResources.cs +++ b/osu.Game.Tests/Skins/TestSceneSkinResources.cs @@ -40,6 +40,16 @@ namespace osu.Game.Tests.Skins AddAssert("sample is non-null", () => skin.GetSample(new SampleInfo(@"sample")) != null); } + [Test] + public void TestRetrievalWithConflictingFilenames() + { + ISkin skin = null!; + + AddStep("import skin", () => skin = importSkinFromArchives(@"conflicting-filenames-skin.osk")); + AddAssert("texture is non-null", () => skin.GetTexture(@"spinner-osu") != null); + AddAssert("sample is non-null", () => skin.GetSample(new SampleInfo(@"spinner-osu")) != null); + } + [Test] public void TestSampleRetrievalOrder() { From 845bbf55fe5d48293afb159c603a177d00bffb65 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Thu, 26 Jan 2023 21:22:06 -0800 Subject: [PATCH 234/430] Add failing beatmap listing search on initial open test --- .../Visual/Navigation/TestSceneScreenNavigation.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index 7bde2e747d..0d081e8138 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -563,6 +563,18 @@ namespace osu.Game.Tests.Visual.Navigation AddUntilStep("featured artist filter is off", () => !getBeatmapListingOverlay().ChildrenOfType().First().Current.Contains(SearchGeneral.FeaturedArtists)); } + [Test] + public void TestBeatmapListingLinkSearchOnInitialOpen() + { + BeatmapListingOverlay getBeatmapListingOverlay() => Game.ChildrenOfType().FirstOrDefault(); + + AddStep("open beatmap overlay with test query", () => Game.SearchBeatmapSet("test")); + + AddUntilStep("wait for beatmap overlay to load", () => getBeatmapListingOverlay()?.State.Value == Visibility.Visible); + + AddAssert("beatmap overlay sorted by relevance", () => getBeatmapListingOverlay().ChildrenOfType().Single().Current.Value == SortCriteria.Relevance); + } + [Test] public void TestMainOverlaysClosesNotificationOverlay() { From 610d2f9dc7346ba8d634670f39bb2ffeeffcd037 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Thu, 26 Jan 2023 21:30:51 -0800 Subject: [PATCH 235/430] Fix beatmap listing potentially not sorting by relevance when searching via metadata --- .../Overlays/BeatmapListing/BeatmapListingSortTabControl.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs index 34e0408db6..0c2637ded3 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs @@ -3,6 +3,7 @@ #nullable disable +using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; @@ -20,9 +21,9 @@ namespace osu.Game.Overlays.BeatmapListing private SearchCategory? lastCategory; private bool? lastHasQuery; - protected override void LoadComplete() + [BackgroundDependencyLoader] + private void load() { - base.LoadComplete(); Reset(SearchCategory.Leaderboard, false); } From 20f4061e303774455802bfbae69313645e19fc8c Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 29 Jan 2023 00:24:05 +0300 Subject: [PATCH 236/430] Move ongoing operation wait step to proper place --- .../Visual/Multiplayer/QueueModeTestScene.cs | 2 ++ .../Multiplayer/TestSceneAllPlayersQueueMode.cs | 15 --------------- .../Multiplayer/TestSceneHostOnlyQueueMode.cs | 13 ------------- 3 files changed, 2 insertions(+), 28 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs b/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs index 0e9863a9f5..0f1ba9ba75 100644 --- a/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs +++ b/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs @@ -16,6 +16,7 @@ using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; +using osu.Game.Screens.OnlinePlay; using osu.Game.Screens.OnlinePlay.Lounge; using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Screens.OnlinePlay.Multiplayer.Match; @@ -85,6 +86,7 @@ namespace osu.Game.Tests.Visual.Multiplayer ClickButtonWhenEnabled(); AddUntilStep("wait for join", () => MultiplayerClient.RoomJoined); + AddUntilStep("wait for ongoing operation to complete", () => !(CurrentScreen as OnlinePlayScreen).ChildrenOfType().Single().InProgress.Value); } [Test] diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs index 6da9d37648..869b8bb328 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs @@ -15,7 +15,6 @@ using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Screens.OnlinePlay; using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Screens.OnlinePlay.Multiplayer.Match; using osu.Game.Screens.Play; @@ -44,14 +43,6 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] - [FlakyTest] - /* - * TearDown : System.TimeoutException : "wait for ongoing operation to complete" timed out - * --TearDown - * at osu.Framework.Testing.Drawables.Steps.UntilStepButton.<>c__DisplayClass11_0.<.ctor>b__0() - * at osu.Framework.Testing.Drawables.Steps.StepButton.PerformStep(Boolean userTriggered) - * at osu.Framework.Testing.TestScene.runNextStep(Action onCompletion, Action`1 onError, Func`2 stopCondition) - */ public void TestItemAddedToTheEndOfQueue() { addItem(() => OtherBeatmap); @@ -64,7 +55,6 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] - [FlakyTest] // See above public void TestNextItemSelectedAfterGameplayFinish() { addItem(() => OtherBeatmap); @@ -82,7 +72,6 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] - [FlakyTest] // See above public void TestItemsNotClearedWhenSwitchToHostOnlyMode() { addItem(() => OtherBeatmap); @@ -98,7 +87,6 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] - [FlakyTest] // See above public void TestCorrectItemSelectedAfterNewItemAdded() { addItem(() => OtherBeatmap); @@ -106,7 +94,6 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] - [FlakyTest] // See above public void TestCorrectRulesetSelectedAfterNewItemAdded() { addItem(() => OtherBeatmap, new CatchRuleset().RulesetInfo); @@ -124,7 +111,6 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] - [FlakyTest] // See above public void TestCorrectModsSelectedAfterNewItemAdded() { addItem(() => OtherBeatmap, mods: new Mod[] { new OsuModDoubleTime() }); @@ -153,7 +139,6 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("wait for song select", () => (songSelect = CurrentSubScreen as Screens.Select.SongSelect) != null); AddUntilStep("wait for loaded", () => songSelect.AsNonNull().BeatmapSetsLoaded); - AddUntilStep("wait for ongoing operation to complete", () => !(CurrentScreen as OnlinePlayScreen).ChildrenOfType().Single().InProgress.Value); if (ruleset != null) AddStep($"set {ruleset.Name} ruleset", () => songSelect.AsNonNull().Ruleset.Value = ruleset); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs index dc36f539e3..78baa4a39b 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs @@ -50,14 +50,6 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] - [FlakyTest] - /* - * TearDown : System.TimeoutException : "wait for ongoing operation to complete" timed out - * --TearDown - * at osu.Framework.Testing.Drawables.Steps.UntilStepButton.<>c__DisplayClass11_0.<.ctor>b__0() - * at osu.Framework.Testing.Drawables.Steps.StepButton.PerformStep(Boolean userTriggered) - * at osu.Framework.Testing.TestScene.runNextStep(Action onCompletion, Action`1 onError, Func`2 stopCondition) - */ public void TestItemStillSelectedAfterChangeToSameBeatmap() { selectNewItem(() => InitialBeatmap); @@ -66,7 +58,6 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] - [FlakyTest] // See above public void TestItemStillSelectedAfterChangeToOtherBeatmap() { selectNewItem(() => OtherBeatmap); @@ -75,7 +66,6 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] - [FlakyTest] // See above public void TestOnlyLastItemChangedAfterGameplayFinished() { RunGameplay(); @@ -90,7 +80,6 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] - [FlakyTest] // See above public void TestAddItemsAsHost() { addItem(() => OtherBeatmap); @@ -115,7 +104,6 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("wait for song select", () => CurrentSubScreen is Screens.Select.SongSelect select && select.BeatmapSetsLoaded); BeatmapInfo otherBeatmap = null; - AddUntilStep("wait for ongoing operation to complete", () => !(CurrentScreen as OnlinePlayScreen).ChildrenOfType().Single().InProgress.Value); AddStep("select other beatmap", () => ((Screens.Select.SongSelect)CurrentSubScreen).FinaliseSelection(otherBeatmap = beatmap())); AddUntilStep("wait for return to match", () => CurrentSubScreen is MultiplayerMatchSubScreen); @@ -131,7 +119,6 @@ namespace osu.Game.Tests.Visual.Multiplayer }); AddUntilStep("wait for song select", () => CurrentSubScreen is Screens.Select.SongSelect select && select.BeatmapSetsLoaded); - AddUntilStep("wait for ongoing operation to complete", () => !(CurrentScreen as OnlinePlayScreen).ChildrenOfType().Single().InProgress.Value); AddStep("select other beatmap", () => ((Screens.Select.SongSelect)CurrentSubScreen).FinaliseSelection(beatmap())); AddUntilStep("wait for return to match", () => CurrentSubScreen is MultiplayerMatchSubScreen); } From 41f5e5143af134be4a018f0830c68a90c479c2fa Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Mon, 30 Jan 2023 12:56:39 +0100 Subject: [PATCH 237/430] 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 238/430] 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 9e7f9c86cabfae4d82499df1d384e3d119f8d7f3 Mon Sep 17 00:00:00 2001 From: itsMapleLeaf <19603573+itsMapleLeaf@users.noreply.github.com> Date: Mon, 30 Jan 2023 11:14:29 -0600 Subject: [PATCH 239/430] flat hold tail --- .../Skinning/Argon/ArgonHoldNoteTailPiece.cs | 71 +------------------ 1 file changed, 2 insertions(+), 69 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs index b2cccfac26..74b4a7b661 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs @@ -1,84 +1,17 @@ // 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.Framework.Graphics.Shapes; -using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.UI.Scrolling; -using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.Skinning.Argon { internal partial class ArgonHoldNoteTailPiece : CompositeDrawable { - private readonly IBindable direction = new Bindable(); - private readonly IBindable accentColour = new Bindable(); - - private readonly Container shadeContainer; - private readonly Circle hitLine; - public ArgonHoldNoteTailPiece() { - RelativeSizeAxes = Axes.X; + // holds end at the middle of the tail, + // so we do * 2 pull up the hold body to be the height of a note Height = ArgonNotePiece.NOTE_HEIGHT * 2; - - CornerRadius = ArgonNotePiece.CORNER_RADIUS; - Masking = true; - - InternalChildren = new Drawable[] - { - shadeContainer = new Container - { - RelativeSizeAxes = Axes.Both, - Height = 0.5f, - CornerRadius = ArgonNotePiece.CORNER_RADIUS, - Masking = true, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.4f, - }, - }, - }, - hitLine = new Circle - { - RelativeSizeAxes = Axes.X, - Height = ArgonNotePiece.CORNER_RADIUS * 2, - }, - }; - } - - [BackgroundDependencyLoader(true)] - private void load(IScrollingInfo scrollingInfo, DrawableHitObject? drawableObject) - { - direction.BindTo(scrollingInfo.Direction); - direction.BindValueChanged(onDirectionChanged, true); - - if (drawableObject != null) - { - accentColour.BindTo(drawableObject.AccentColour); - accentColour.BindValueChanged(onAccentChanged, true); - } - } - - private void onDirectionChanged(ValueChangedEvent direction) - { - hitLine.Anchor = hitLine.Origin = - shadeContainer.Anchor = shadeContainer.Origin = - direction.NewValue == ScrollingDirection.Up - ? Anchor.TopCentre - : Anchor.BottomCentre; - } - - private void onAccentChanged(ValueChangedEvent accent) - { - hitLine.Colour = accent.NewValue; } } } From 55a045b2b24443b4fef1e0e343dfe85d37ee91b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 28 Jan 2023 15:59:50 +0100 Subject: [PATCH 240/430] Adjust beatmap skin resources test to facilitate loading many --- .../Skins/TestSceneBeatmapSkinResources.cs | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs b/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs index 5256bcb3af..0bcaf217ab 100644 --- a/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs +++ b/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.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. -#nullable disable - using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio.Track; using osu.Framework.Extensions; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Testing; using osu.Game.Audio; using osu.Game.Beatmaps; @@ -20,29 +19,26 @@ namespace osu.Game.Tests.Skins public partial class TestSceneBeatmapSkinResources : OsuTestScene { [Resolved] - private BeatmapManager beatmaps { get; set; } + private BeatmapManager beatmaps { get; set; } = null!; - private IWorkingBeatmap beatmap; - - [BackgroundDependencyLoader] - private void load() + [Test] + public void TestRetrieveOggAudio() { - var imported = beatmaps.Import(new ImportTask(TestResources.OpenResource("Archives/ogg-beatmap.osz"), "ogg-beatmap.osz")).GetResultSafely(); + IWorkingBeatmap beatmap = null!; - imported?.PerformRead(s => + AddStep("import beatmap", () => beatmap = importBeatmapFromArchives(@"ogg-beatmap.osz")); + AddAssert("sample is non-null", () => beatmap.Skin.GetSample(new SampleInfo(@"sample")) != null); + AddAssert("track is non-null", () => { - beatmap = beatmaps.GetWorkingBeatmap(s.Beatmaps[0]); + using (var track = beatmap.LoadTrack()) + return track is not TrackVirtual; }); } - [Test] - public void TestRetrieveOggSample() => AddAssert("sample is non-null", () => beatmap.Skin.GetSample(new SampleInfo("sample")) != null); - - [Test] - public void TestRetrieveOggTrack() => AddAssert("track is non-null", () => + private IWorkingBeatmap importBeatmapFromArchives(string filename) { - using (var track = beatmap.LoadTrack()) - return track is not TrackVirtual; - }); + var imported = beatmaps.Import(new ImportTask(TestResources.OpenResource($@"Archives/{filename}"), filename)).GetResultSafely(); + return imported.AsNonNull().PerformRead(s => beatmaps.GetWorkingBeatmap(s.Beatmaps[0])); + } } } From a8f828d203f8efab41d9ce23e2e34cc76825db3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 28 Jan 2023 16:02:11 +0100 Subject: [PATCH 241/430] Add another failing test case --- .../Archives/conflicting-filenames-beatmap.osz | Bin 0 -> 6604 bytes .../Skins/TestSceneBeatmapSkinResources.cs | 10 ++++++++++ 2 files changed, 10 insertions(+) create mode 100644 osu.Game.Tests/Resources/Archives/conflicting-filenames-beatmap.osz diff --git a/osu.Game.Tests/Resources/Archives/conflicting-filenames-beatmap.osz b/osu.Game.Tests/Resources/Archives/conflicting-filenames-beatmap.osz new file mode 100644 index 0000000000000000000000000000000000000000..c6b5f083ff6e5f17cb632ae21a29d2ebe58eb963 GIT binary patch literal 6604 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 literal 0 HcmV?d00001 diff --git a/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs b/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs index 0bcaf217ab..d9212386c3 100644 --- a/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs +++ b/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs @@ -35,6 +35,16 @@ namespace osu.Game.Tests.Skins }); } + [Test] + public void TestRetrievalWithConflictingFilenames() + { + IWorkingBeatmap beatmap = null!; + + AddStep("import beatmap", () => beatmap = importBeatmapFromArchives(@"conflicting-filenames-beatmap.osz")); + AddAssert("texture is non-null", () => beatmap.Skin.GetTexture(@"spinner-osu") != null); + AddAssert("sample is non-null", () => beatmap.Skin.GetSample(new SampleInfo(@"spinner-osu")) != null); + } + private IWorkingBeatmap importBeatmapFromArchives(string filename) { var imported = beatmaps.Import(new ImportTask(TestResources.OpenResource($@"Archives/{filename}"), filename)).GetResultSafely(); From c5e1f54185b6ad3391f61b409035d06f79aaca46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 28 Jan 2023 21:16:22 +0100 Subject: [PATCH 242/430] Fix sample store creation mutating shared resource store --- .../Rulesets/TestSceneDrawableRulesetDependencies.cs | 2 ++ osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs | 2 ++ osu.Game/Skinning/Skin.cs | 9 ++++++--- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Rulesets/TestSceneDrawableRulesetDependencies.cs b/osu.Game.Tests/Rulesets/TestSceneDrawableRulesetDependencies.cs index 3fba21050e..5cfcca303f 100644 --- a/osu.Game.Tests/Rulesets/TestSceneDrawableRulesetDependencies.cs +++ b/osu.Game.Tests/Rulesets/TestSceneDrawableRulesetDependencies.cs @@ -150,6 +150,8 @@ namespace osu.Game.Tests.Rulesets public IBindable AggregateTempo => throw new NotImplementedException(); public int PlaybackConcurrency { get; set; } + + public void AddExtension(string extension) => throw new NotImplementedException(); } private class TestShaderManager : ShaderManager diff --git a/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs b/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs index c50f63c3b2..96b02ee4dc 100644 --- a/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs +++ b/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs @@ -157,6 +157,8 @@ namespace osu.Game.Rulesets.UI set => throw new NotSupportedException(); } + public void AddExtension(string extension) => throw new NotSupportedException(); + public void Dispose() { if (primary.IsNotNull()) primary.Dispose(); diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index 419dacadfd..37e98946c9 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -69,12 +69,15 @@ namespace osu.Game.Skinning storage ??= realmBackedStorage = new RealmBackedResourceStore(SkinInfo, resources.Files, resources.RealmAccess); var samples = resources.AudioManager?.GetSampleStore(storage); + if (samples != null) + { samples.PlaybackConcurrency = OsuGameBase.SAMPLE_CONCURRENCY; - // osu-stable performs audio lookups in order of wav -> mp3 -> ogg. - // The GetSampleStore() call above internally adds wav and mp3, so ogg is added at the end to ensure expected ordering. - (storage as ResourceStore)?.AddExtension("ogg"); + // osu-stable performs audio lookups in order of wav -> mp3 -> ogg. + // The GetSampleStore() call above internally adds wav and mp3, so ogg is added at the end to ensure expected ordering. + samples.AddExtension(@"ogg"); + } Samples = samples; Textures = new TextureStore(resources.Renderer, new MaxDimensionLimitedTextureLoaderStore(resources.CreateTextureLoaderStore(storage))); From b1cbe20cd82e93533b73ccfeeac17986129824a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 28 Jan 2023 21:16:37 +0100 Subject: [PATCH 243/430] Adjust markdown text flow to framework-side changes --- .../Containers/Markdown/OsuMarkdownTextFlowContainer.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs index 5f5b9acf56..dbc358882c 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs @@ -42,8 +42,12 @@ namespace osu.Game.Graphics.Containers.Markdown protected override void AddFootnoteBacklink(FootnoteLink footnoteBacklink) => AddDrawable(new OsuMarkdownFootnoteBacklink(footnoteBacklink)); - protected override SpriteText CreateEmphasisedSpriteText(bool bold, bool italic) - => CreateSpriteText().With(t => t.Font = t.Font.With(weight: bold ? FontWeight.Bold : FontWeight.Regular, italics: italic)); + protected override void ApplyEmphasisedCreationParameters(SpriteText spriteText, bool bold, bool italic) + { + base.ApplyEmphasisedCreationParameters(spriteText, bold, italic); + + spriteText.Font = spriteText.Font.With(weight: bold ? FontWeight.Bold : FontWeight.Regular, italics: italic); + } protected override void AddCustomComponent(CustomContainerInline inline) { From 54d5d4e7c6a96fb4cd1d48d8b89ad6d508e181b0 Mon Sep 17 00:00:00 2001 From: Cootz Date: Tue, 31 Jan 2023 07:06:26 +0300 Subject: [PATCH 244/430] Fix for the issue --- .../Settings/Sections/Maintenance/MigrationSelectScreen.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs index 80bf292057..57eb5ce60e 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs @@ -47,6 +47,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance var directoryInfos = target.GetDirectories(); var fileInfos = target.GetFiles(); + //With an empty disk (mb flash drive), this if could be false if (directoryInfos.Length > 0 || fileInfos.Length > 0) { // Quick test for whether there's already an osu! install at the target path. @@ -65,7 +66,11 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance return; } - target = target.CreateSubdirectory("osu-lazer"); + //Check for a root directory + if (target.Parent == null) + target = Directory.CreateDirectory(Path.Combine(target.FullName, "osu-lazer")); + else + target = target.CreateSubdirectory("osu-lazer"); } } catch (Exception e) From b18652b25fa366ea9191db55af53b43fc02fcb30 Mon Sep 17 00:00:00 2001 From: Cootz Date: Tue, 31 Jan 2023 10:14:21 +0300 Subject: [PATCH 245/430] CreateSubDirectory removed. Fixes the empty root issue --- .../Sections/Maintenance/MigrationSelectScreen.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs index 57eb5ce60e..159a99809d 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs @@ -47,8 +47,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance var directoryInfos = target.GetDirectories(); var fileInfos = target.GetFiles(); - //With an empty disk (mb flash drive), this if could be false - if (directoryInfos.Length > 0 || fileInfos.Length > 0) + if (directoryInfos.Length > 0 || fileInfos.Length > 0 || target.Parent == null) { // Quick test for whether there's already an osu! install at the target path. if (fileInfos.Any(f => f.Name == OsuGameBase.CLIENT_DATABASE_FILENAME)) @@ -66,11 +65,8 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance return; } - //Check for a root directory - if (target.Parent == null) - target = Directory.CreateDirectory(Path.Combine(target.FullName, "osu-lazer")); - else - target = target.CreateSubdirectory("osu-lazer"); + //We aren't using CreateSubDirectory due to the flaw with a root of a drive + target = Directory.CreateDirectory(Path.Combine(target.FullName, "osu-lazer")); } } catch (Exception e) From 3d8b35184fe2edf3dd8a4d0a8ad52a9b6f833999 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 31 Jan 2023 16:24:06 +0900 Subject: [PATCH 246/430] 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 71944065bf..4bdf5d68c5 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -10,7 +10,7 @@ true - +