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/376] 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/376] 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/376] 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/376] 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/376] 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/376] 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/376] 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/376] 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 9c611019b37d770355ccee2c23088238ac47d8e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20K=C3=A4llberg?= Date: Tue, 11 Oct 2022 09:30:32 +0200 Subject: [PATCH 009/376] Toolbar localisation --- osu.Game/Localisation/HomeStrings.cs | 24 +++++++++++++++++++ osu.Game/Localisation/RulesetStrings.cs | 20 ++++++++++++++++ .../Overlays/Toolbar/ToolbarHomeButton.cs | 5 ++-- .../Toolbar/ToolbarRulesetTabButton.cs | 4 +++- 4 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 osu.Game/Localisation/HomeStrings.cs create mode 100644 osu.Game/Localisation/RulesetStrings.cs diff --git a/osu.Game/Localisation/HomeStrings.cs b/osu.Game/Localisation/HomeStrings.cs new file mode 100644 index 0000000000..4a2cea00ca --- /dev/null +++ b/osu.Game/Localisation/HomeStrings.cs @@ -0,0 +1,24 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Localisation; + +namespace osu.Game.Localisation +{ + public static class HomeStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.Home"; + + /// + /// "home" + /// + public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"home"); + + /// + /// "return to the main menu" + /// + public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"return to the main menu"); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} \ No newline at end of file diff --git a/osu.Game/Localisation/RulesetStrings.cs b/osu.Game/Localisation/RulesetStrings.cs new file mode 100644 index 0000000000..201831cd91 --- /dev/null +++ b/osu.Game/Localisation/RulesetStrings.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.Localisation; + +namespace osu.Game.Localisation +{ + public static class RulesetStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.Ruleset"; + + /// + /// "play some" + /// + + public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"play some"); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} \ No newline at end of file diff --git a/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs b/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs index f170ec84ac..52fa83e37a 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs @@ -5,6 +5,7 @@ using osu.Framework.Allocation; using osu.Game.Input.Bindings; +using osu.Game.Localisation; namespace osu.Game.Overlays.Toolbar { @@ -19,8 +20,8 @@ namespace osu.Game.Overlays.Toolbar [BackgroundDependencyLoader] private void load() { - TooltipMain = "home"; - TooltipSub = "return to the main menu"; + TooltipMain = HomeStrings.HeaderTitle; + TooltipSub = HomeStrings.HeaderDescription; SetIcon("Icons/Hexacons/home"); } } diff --git a/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs b/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs index 31c6802fda..101bba95cc 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs @@ -9,6 +9,8 @@ using osu.Game.Rulesets; using osuTK.Graphics; using osu.Framework.Graphics; using osu.Framework.Input.Events; +using osu.Framework.Localisation; +using osu.Game.Localisation; namespace osu.Game.Overlays.Toolbar { @@ -29,7 +31,7 @@ namespace osu.Game.Overlays.Toolbar var rInstance = value.CreateInstance(); ruleset.TooltipMain = rInstance.Description; - ruleset.TooltipSub = $"play some {rInstance.Description}"; + ruleset.TooltipSub = LocalisableString.Format("{0} {1}", RulesetStrings.HeaderDescription, ($"{rInstance.Description}")); ruleset.SetIcon(rInstance.CreateIcon()); } From 63e651130af1954d7f8ce5ac1923a95abb2bc926 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20K=C3=A4llberg?= Date: Tue, 11 Oct 2022 10:59:07 +0200 Subject: [PATCH 010/376] Grouped localisation strings --- osu.Game/Localisation/HomeStrings.cs | 24 ------------------- osu.Game/Localisation/RulesetStrings.cs | 20 ---------------- osu.Game/Localisation/ToolbarStrings.cs | 16 +++++++++++++ .../Overlays/Toolbar/ToolbarHomeButton.cs | 4 ++-- .../Toolbar/ToolbarRulesetTabButton.cs | 8 +++---- 5 files changed, 22 insertions(+), 50 deletions(-) delete mode 100644 osu.Game/Localisation/HomeStrings.cs delete mode 100644 osu.Game/Localisation/RulesetStrings.cs diff --git a/osu.Game/Localisation/HomeStrings.cs b/osu.Game/Localisation/HomeStrings.cs deleted file mode 100644 index 4a2cea00ca..0000000000 --- a/osu.Game/Localisation/HomeStrings.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Localisation; - -namespace osu.Game.Localisation -{ - public static class HomeStrings - { - private const string prefix = @"osu.Game.Resources.Localisation.Home"; - - /// - /// "home" - /// - public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"home"); - - /// - /// "return to the main menu" - /// - public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"return to the main menu"); - - private static string getKey(string key) => $"{prefix}:{key}"; - } -} \ No newline at end of file diff --git a/osu.Game/Localisation/RulesetStrings.cs b/osu.Game/Localisation/RulesetStrings.cs deleted file mode 100644 index 201831cd91..0000000000 --- a/osu.Game/Localisation/RulesetStrings.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Localisation; - -namespace osu.Game.Localisation -{ - public static class RulesetStrings - { - private const string prefix = @"osu.Game.Resources.Localisation.Ruleset"; - - /// - /// "play some" - /// - - public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"play some"); - - private static string getKey(string key) => $"{prefix}:{key}"; - } -} \ No newline at end of file diff --git a/osu.Game/Localisation/ToolbarStrings.cs b/osu.Game/Localisation/ToolbarStrings.cs index 6dc8a1e50c..b76c643332 100644 --- a/osu.Game/Localisation/ToolbarStrings.cs +++ b/osu.Game/Localisation/ToolbarStrings.cs @@ -19,6 +19,22 @@ namespace osu.Game.Localisation /// public static LocalisableString Connecting => new TranslatableString(getKey(@"connecting"), @"Connecting..."); + /// + /// "home" + /// + public static LocalisableString HomeHeaderTitle => new TranslatableString(getKey(@"header_title"), @"home"); + + /// + /// "return to the main menu" + /// + public static LocalisableString HomeHeaderDescription => new TranslatableString(getKey(@"header_description"), @"return to the main menu"); + + /// + /// "play some" + /// + + public static LocalisableString RulesetHeaderDescription => new TranslatableString(getKey(@"header_description"), @"play some"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs b/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs index 52fa83e37a..959706b805 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs @@ -20,8 +20,8 @@ namespace osu.Game.Overlays.Toolbar [BackgroundDependencyLoader] private void load() { - TooltipMain = HomeStrings.HeaderTitle; - TooltipSub = HomeStrings.HeaderDescription; + TooltipMain = ToolbarStrings.HomeHeaderTitle; + TooltipSub = ToolbarStrings.HomeHeaderDescription; SetIcon("Icons/Hexacons/home"); } } diff --git a/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs b/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs index 101bba95cc..bffd8b96e5 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs @@ -3,14 +3,14 @@ #nullable disable +using osu.Framework.Graphics; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.UserInterface; -using osu.Game.Rulesets; -using osuTK.Graphics; -using osu.Framework.Graphics; using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Game.Localisation; +using osu.Game.Rulesets; +using osuTK.Graphics; namespace osu.Game.Overlays.Toolbar { @@ -31,7 +31,7 @@ namespace osu.Game.Overlays.Toolbar var rInstance = value.CreateInstance(); ruleset.TooltipMain = rInstance.Description; - ruleset.TooltipSub = LocalisableString.Format("{0} {1}", RulesetStrings.HeaderDescription, ($"{rInstance.Description}")); + ruleset.TooltipSub = LocalisableString.Format("{0} {1}", ToolbarStrings.RulesetHeaderDescription, ($"{rInstance.Description}")); ruleset.SetIcon(rInstance.CreateIcon()); } 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 011/376] 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 012/376] 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 013/376] 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 014/376] 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 015/376] 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 016/376] 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 017/376] 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 018/376] 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 ffbe68bd26f8e4dbe154037ad47c15e972699676 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Sun, 11 Dec 2022 22:08:48 +0100 Subject: [PATCH 019/376] Add judgementTally to HUD overlay --- .../HUD/JudgementCounter/JudgementTally.cs | 56 +++++++++++++++++++ osu.Game/Screens/Play/HUDOverlay.cs | 5 ++ 2 files changed, 61 insertions(+) create mode 100644 osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs new file mode 100644 index 0000000000..2bc89aeea1 --- /dev/null +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs @@ -0,0 +1,56 @@ + + + +// 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.Bindables; +using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.UI; + +namespace osu.Game.Screens.Play.HUD.JudgementCounter +{ + public partial class JudgementTally : CompositeDrawable + { + [Resolved] + private ScoreProcessor scoreProcessor { get; set; } = null!; + + public List Results = new List(); + + [BackgroundDependencyLoader] + private void load(DrawableRuleset ruleset) + { + foreach (var result in ruleset.Ruleset.GetHitResults()) + { + Results.Add(new JudgementCounterInfo + { + ResultInfo = (result.result, result.displayName), + ResultCount = new BindableInt(), + }); + } + } + + protected override void LoadComplete() + { + base.LoadComplete(); + scoreProcessor.NewJudgement += judgement => + { + foreach (JudgementCounterInfo result in Results.Where(result => result.ResultInfo.Type == judgement.Type)) + { + result.ResultCount.Value++; + } + }; + scoreProcessor.JudgementReverted += judgement => + { + foreach (JudgementCounterInfo result in Results.Where(result => result.ResultInfo.Type == judgement.Type)) + { + result.ResultCount.Value--; + } + }; + } + } +} diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 4c2483a0e6..816b8b2543 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -24,6 +24,7 @@ using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Play.HUD.ClicksPerSecond; using osu.Game.Skinning; using osuTK; +using JudgementTally = osu.Game.Screens.Play.HUD.JudgementCounter.JudgementTally; namespace osu.Game.Screens.Play { @@ -58,6 +59,9 @@ namespace osu.Game.Screens.Play [Cached] private readonly ClicksPerSecondCalculator clicksPerSecondCalculator; + [Cached] + private readonly JudgementTally tally; + public Bindable ShowHealthBar = new Bindable(true); private readonly DrawableRuleset drawableRuleset; @@ -146,6 +150,7 @@ namespace osu.Game.Screens.Play Spacing = new Vector2(5) }, clicksPerSecondCalculator = new ClicksPerSecondCalculator(), + tally = new JudgementTally() }; hideTargets = new List { mainComponents, KeyCounter, topRightElements }; From f798951f0974b49592d10b1f7959d6e0e0a8ce46 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Sun, 11 Dec 2022 22:09:14 +0100 Subject: [PATCH 020/376] Create Judgement Info struct --- .../HUD/JudgementCounter/JudgementCounterInfo.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterInfo.cs diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterInfo.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterInfo.cs new file mode 100644 index 0000000000..45f89c30d2 --- /dev/null +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterInfo.cs @@ -0,0 +1,16 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; +using osu.Framework.Localisation; +using osu.Game.Rulesets.Scoring; + +namespace osu.Game.Screens.Play.HUD.JudgementCounter +{ + public struct JudgementCounterInfo + { + public (HitResult Type, LocalisableString Displayname) ResultInfo { get; set; } + + public BindableInt ResultCount { get; set; } + } +} From 4c17b27273b638e2f271782be2cb50b8abf59f2b Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Sun, 11 Dec 2022 23:47:17 +0100 Subject: [PATCH 021/376] Add Display, Counter, Tests --- .../Gameplay/TestSceneJudgementCounter.cs | 136 ++++++++++++++++++ .../HUD/JudgementCounter/JudgementCounter.cs | 118 +++++++++++++++ .../JudgementCounterDisplay.cs | 133 +++++++++++++++++ .../HUD/JudgementCounter/JudgementTally.cs | 8 +- 4 files changed, 391 insertions(+), 4 deletions(-) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs create mode 100644 osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs create mode 100644 osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs new file mode 100644 index 0000000000..27f2362047 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs @@ -0,0 +1,136 @@ +// 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.Diagnostics; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Mania; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Osu.Judgements; +using osu.Game.Rulesets.Scoring; +using osu.Game.Screens.Play.HUD.JudgementCounter; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public partial class TestSceneJudgementCounter : OsuTestScene + { + private ScoreProcessor scoreProcessor = null!; + private JudgementTally judgementTally = null!; + private TestJudgementCounterDisplay counter = null!; + + private readonly Bindable lastJudgementResult = new Bindable(); + + private int iteration; + + [SetUpSteps] + public void SetupSteps() => AddStep("Create components", () => + { + var ruleset = CreateRuleset(); + + Debug.Assert(ruleset != null); + + scoreProcessor = new ScoreProcessor(ruleset); + Child = new DependencyProvidingContainer + { + RelativeSizeAxes = Axes.Both, + CachedDependencies = new (Type, object)[] { (typeof(ScoreProcessor), scoreProcessor), (typeof(Ruleset), ruleset) }, + Children = new Drawable[] + { + judgementTally = new JudgementTally(), + new DependencyProvidingContainer + { + RelativeSizeAxes = Axes.Both, + CachedDependencies = new (Type, object)[] { (typeof(JudgementTally), judgementTally) }, + Child = counter = new TestJudgementCounterDisplay + { + Margin = new MarginPadding { Top = 100 }, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre + } + } + }, + }; + }); + + protected override Ruleset CreateRuleset() => new ManiaRuleset(); + + private void applyOneJudgement(HitResult result) + { + lastJudgementResult.Value = new OsuJudgementResult(new HitObject + { + StartTime = iteration * 10000 + }, new OsuJudgement()) + { + Type = result, + }; + scoreProcessor.ApplyResult(lastJudgementResult.Value); + + iteration++; + } + + [Test] + public void TestAddJudgementsToCounters() + { + AddRepeatStep("Add judgement", () => applyOneJudgement(HitResult.Great), 2); + AddRepeatStep("Add judgement", () => applyOneJudgement(HitResult.Miss), 2); + AddRepeatStep("Add judgement", () => applyOneJudgement(HitResult.Meh), 2); + AddRepeatStep("Add judgement", () => applyOneJudgement(HitResult.LargeTickHit), 2); + AddStep("Show all judgements", () => counter.Mode.Value = JudgementCounterDisplay.DisplayMode.All); + AddAssert("Check value added whilst hidden", () => hiddenCount() == 2); + } + + [Test] + public void TestAddWhilstHidden() + { + AddRepeatStep("Add judgement", () => applyOneJudgement(HitResult.LargeTickHit), 2); + AddAssert("Check value added whilst hidden", () => hiddenCount() == 2); + AddStep("Show all judgements", () => counter.Mode.Value = JudgementCounterDisplay.DisplayMode.All); + } + + [Test] + public void TestChangeFlowDirection() + { + AddStep("Set direction vertical", () => counter.Direction.Value = FillDirection.Vertical); + AddStep("Set direction horizontal", () => counter.Direction.Value = FillDirection.Vertical); + } + + [Test] + public void TestHideJudgementNames() + { + AddStep("Hide judgement names", () => counter.ShowName.Value = false); + } + + [Test] + public void TestHideMaxValue() + { + AddStep("Hide max judgement", () => counter.ShowMax.Value = false); + AddStep("Show max judgement", () => counter.ShowMax.Value = true); + } + + [Test] + public void TestCycleDisplayModes() + { + AddStep("Show all judgements", () => counter.Mode.Value = JudgementCounterDisplay.DisplayMode.All); + AddStep("Show normal judgements", () => counter.Mode.Value = JudgementCounterDisplay.DisplayMode.Normal); + AddStep("Show basic judgements", () => counter.Mode.Value = JudgementCounterDisplay.DisplayMode.Simple); + } + + private int hiddenCount() + { + var num = counter.JudgementContainer.Children.OfType().First(child => child.Result.ResultInfo.Type == HitResult.LargeTickHit); + return num.Result.ResultCount.Value; + } + + private partial class TestJudgementCounterDisplay : JudgementCounterDisplay + { + public new FillFlowContainer JudgementContainer => base.JudgementContainer; + } + } +} diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs new file mode 100644 index 0000000000..d9709eb88a --- /dev/null +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs @@ -0,0 +1,118 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Rulesets.Scoring; + +namespace osu.Game.Screens.Play.HUD.JudgementCounter +{ + public partial class JudgementCounter : OverlayContainer + { + public BindableBool ShowName = new BindableBool(); + public Bindable Direction = new Bindable(); + + public readonly JudgementCounterInfo Result; + + public JudgementCounter(JudgementCounterInfo result) + { + Result = result; + } + + private OsuSpriteText resultName = null!; + private FillFlowContainer flowContainer = null!; + private JudgementRollingCounter counter = null!; + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + AutoSizeAxes = Axes.Both; + InternalChild = flowContainer = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Children = new Drawable[] + { + counter = new JudgementRollingCounter + { + Current = Result.ResultCount + }, + resultName = new OsuSpriteText + { + Font = OsuFont.Numeric.With(size: 8), + Text = Result.ResultInfo.Displayname + } + } + }; + + var result = Result.ResultInfo.Type; + + if (result.IsBasic()) + { + Colour = colours.ForHitResult(Result.ResultInfo.Type); + return; + } + + if (!result.IsBonus()) + { + Colour = colours.PurpleLight; + return; + } + + Colour = colours.PurpleLighter; + } + + protected override void LoadComplete() + { + ShowName.BindValueChanged(value => + { + if (value.NewValue) + { + resultName.Show(); + return; + } + + resultName.Hide(); + }, true); + + Direction.BindValueChanged(direction => + { + flowContainer.Direction = direction.NewValue; + + if (direction.NewValue == FillDirection.Vertical) + { + changeAnchor(Anchor.TopLeft); + return; + } + + changeAnchor(Anchor.BottomLeft); + + void changeAnchor(Anchor anchor) => counter.Anchor = resultName.Anchor = counter.Origin = resultName.Origin = anchor; + }, true); + + base.LoadComplete(); + } + + protected override void PopIn() + { + this.FadeInFromZero(500, Easing.OutQuint); + } + + protected override void PopOut() + { + this.FadeOut(100); + } + + private sealed partial class JudgementRollingCounter : RollingCounter + { + protected override OsuSpriteText CreateSpriteText() + => base.CreateSpriteText().With(s => s.Font = s.Font.With(fixedWidth: true, size: 16)); + + protected override double RollingDuration => 750; + } + } +} diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs new file mode 100644 index 0000000000..b392ce8e04 --- /dev/null +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs @@ -0,0 +1,133 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Configuration; +using osu.Game.Rulesets.Scoring; +using osu.Game.Skinning; +using osuTK; + +namespace osu.Game.Screens.Play.HUD.JudgementCounter +{ + public partial class JudgementCounterDisplay : CompositeDrawable, ISkinnableDrawable + { + public bool UsesFixedAnchor { get; set; } + + [SettingSource("Counter direction")] + public Bindable Direction { get; set; } = new Bindable(); + + [SettingSource("Show judgement names")] + public BindableBool ShowName { get; set; } = new BindableBool(true); + + [SettingSource("Show max judgement")] + public BindableBool ShowMax { get; set; } = new BindableBool(true); + + [SettingSource("Display mode")] + public Bindable Mode { get; set; } = new Bindable(); + + [Resolved] + private JudgementTally tally { get; set; } = null!; + + protected FillFlowContainer JudgementContainer = null!; + + [BackgroundDependencyLoader] + private void load() + { + InternalChild = JudgementContainer = new FillFlowContainer + { + Direction = Direction.Value, + Spacing = new Vector2(10), + AutoSizeAxes = Axes.Both + }; + + foreach (var result in tally.Results) + { + JudgementContainer.Add(createCounter(result)); + } + } + + protected override void Update() + { + Size = JudgementContainer.Size; + base.Update(); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Direction.BindValueChanged(direction => JudgementContainer.Direction = direction.NewValue); + Mode.BindValueChanged(_ => updateCounter(), true); + + ShowMax.BindValueChanged(value => + { + var firstChild = JudgementContainer.Children.FirstOrDefault(); + + if (value.NewValue) + { + firstChild?.Show(); + return; + } + + firstChild?.Hide(); + }, true); + } + + private void updateCounter() + { + var counters = JudgementContainer.Children.OfType().ToList(); + + switch (Mode.Value) + { + case DisplayMode.Simple: + foreach (var counter in counters.Where(counter => counter.Result.ResultInfo.Type.IsBasic())) + counter.Show(); + + foreach (var counter in counters.Where(counter => !counter.Result.ResultInfo.Type.IsBasic())) + counter.Hide(); + + break; + + case DisplayMode.Normal: + foreach (var counter in counters.Where(counter => !counter.Result.ResultInfo.Type.IsBonus())) + counter.Show(); + + foreach (var counter in counters.Where(counter => counter.Result.ResultInfo.Type.IsBonus())) + counter.Hide(); + + break; + + case DisplayMode.All: + foreach (JudgementCounter counter in counters.Where(counter => !counter.IsPresent)) + counter.Show(); + + break; + + default: + throw new ArgumentOutOfRangeException(); + } + } + + public enum DisplayMode + { + Simple, + Normal, + All + } + + private JudgementCounter createCounter(JudgementCounterInfo info) + { + JudgementCounter counter = new JudgementCounter(info) + { + ShowName = { BindTarget = ShowName }, + Direction = { BindTarget = Direction } + }; + return counter; + } + } +} diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs index 2bc89aeea1..9cbeea7a2a 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs @@ -9,8 +9,8 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Scoring; -using osu.Game.Rulesets.UI; namespace osu.Game.Screens.Play.HUD.JudgementCounter { @@ -22,14 +22,14 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter public List Results = new List(); [BackgroundDependencyLoader] - private void load(DrawableRuleset ruleset) + private void load(IBindable working) { - foreach (var result in ruleset.Ruleset.GetHitResults()) + foreach (var result in working.Value.BeatmapInfo.Ruleset.CreateInstance().GetHitResults()) { Results.Add(new JudgementCounterInfo { ResultInfo = (result.result, result.displayName), - ResultCount = new BindableInt(), + ResultCount = new BindableInt() }); } } From 161894da3ba0c26ff1fe7a4473351999c19ba77b Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Sun, 11 Dec 2022 23:58:10 +0100 Subject: [PATCH 022/376] Add more test checks and fix deserialisation test --- .../Archives/modified-default-20221211.osk | Bin 0 -> 1650 bytes osu.Game.Tests/Skins/SkinDeserialisationTest.cs | 4 +++- .../Visual/Gameplay/TestSceneJudgementCounter.cs | 5 ++++- .../HUD/JudgementCounter/JudgementCounter.cs | 10 +++++----- 4 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 osu.Game.Tests/Resources/Archives/modified-default-20221211.osk diff --git a/osu.Game.Tests/Resources/Archives/modified-default-20221211.osk b/osu.Game.Tests/Resources/Archives/modified-default-20221211.osk new file mode 100644 index 0000000000000000000000000000000000000000..07190db267cfcbf0abf44a5eb95b4e43bb0955d2 GIT binary patch literal 1650 zcmWIWW@Zs#U|`^2__41$)V#A{#{nQOh#4fpz)+l>nWvYTm-)2cFptSlz_ogQ(hG;C zH@8F=E%uturR8F1usI>|yvx0fVRLj{`=)5Kh%9yb!m&$#@A~!s>-O!N%@*d~<`;ZP z@f71Xtz$_B3H%Yh#!+{Yz0w_&)Nagm{B6aw>S`{J3j_M*Aq3^;H=}T|8F6)dAv(Ab<5aqY1+2Z>O|HRMo z=|^O*rEI>?cH!LLn%^>Fr~Wd|K|=s@#Vyw=@NZF-`xgcUZ^iK^V0J5 zvWoNbO8Yi)9WoGc{a$y}IG8)v!$>ro{pF)YewP#{EU~$@&tcLdg@3!*&fa)i^sco! zPLyHyi>sTI4dk~oU(sB!EOX<=#;UJuvQd{0EIx8BV)=H}QZEhFs+;}Rb47yQmU*3; zxb^2Bku`pHPySnM)8007O90!Ns(J=g zhwp#q^9Xfu&d)8#&r8iKDF*xC?R4Ml#|8pz?|+J_rMsWl zm~))lvSjXE-romjEqlB4%K|N7_mGKQD$Zv&{jYs`jPJ6-FWs`BcD?Mo z>hJ};;YEEHA3v|2DIJqF!&_tRvP0iLeF`i1#=MHVl)XsLTk+Vxd)4cBw&!h&K3He# zS6$HCz>?8rs8+W+%#T;OMgDgE?3d3^T}rEZTcy8FLbM=h!`nO`R$1@#Nx4(kSx<8N zxwi6P_UTOJ7%7AJpUi9clg&dUGWIrYjS*W`c1P;$wwN`hSKQX+yY+7V|8!rHmvj7` zLiXT}c7?hCHmAB{5i2!U|5{{M>HAWy?eL*^CegCp51!pC{W9-^?UU+Ts&-!(7pF|j z4$Uxlru&KS@nn&HcBOq!zI9*o`p;CpM&irNSISRyFYy;l|L6E~!T*?Flb5U8SDOAP zz97A{JjCdP==5tmp;wL=7M1Jv-49HhY?)Sm%r$}4=Va;jyU`1slUx=}XpwEm6nUVb zc%H|jBgu!ObJ62hD?{h+GUW5RfAHr^y#xbW`wc-olOm_69JfB)IpfIX@-4>uroUz? zQ^DtQ)=Hi-THF6kzeb!+_4#F^7J1$uPry5p|;f1 zQSkropj>mUWReY~TlDD8rhZwUB}upTn8nIe8{If2()ak$1dF(o?Juq^sB5Wxb@_m8!|%4ok*}6K zT=BL4fr+ohoJ~S9Uz}eBZ9jZ#L0o%@#wDL=&$irW@K=rA7M6(ANZGIP>R}+Y)!F-u0p5&E zA`H08T3}>BKqH8PmAvS>(915U9tMWSXHZ@6k_=rddg+1CIv diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs index 27f2362047..885b182a6f 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs @@ -102,9 +102,12 @@ namespace osu.Game.Tests.Visual.Gameplay } [Test] - public void TestHideJudgementNames() + public void TestToggleJudgementNames() { AddStep("Hide judgement names", () => counter.ShowName.Value = false); + AddAssert("Assert hidden", () => counter.JudgementContainer.Children.OfType().First().ResultName.Alpha == 0); + AddStep("Hide judgement names", () => counter.ShowName.Value = true); + AddAssert("Assert shown", () => counter.JudgementContainer.Children.OfType().First().ResultName.Alpha == 1); } [Test] diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs index d9709eb88a..d7bb8939e1 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs @@ -24,7 +24,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter Result = result; } - private OsuSpriteText resultName = null!; + public OsuSpriteText ResultName = null!; private FillFlowContainer flowContainer = null!; private JudgementRollingCounter counter = null!; @@ -41,7 +41,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter { Current = Result.ResultCount }, - resultName = new OsuSpriteText + ResultName = new OsuSpriteText { Font = OsuFont.Numeric.With(size: 8), Text = Result.ResultInfo.Displayname @@ -72,11 +72,11 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter { if (value.NewValue) { - resultName.Show(); + ResultName.Show(); return; } - resultName.Hide(); + ResultName.Hide(); }, true); Direction.BindValueChanged(direction => @@ -91,7 +91,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter changeAnchor(Anchor.BottomLeft); - void changeAnchor(Anchor anchor) => counter.Anchor = resultName.Anchor = counter.Origin = resultName.Origin = anchor; + void changeAnchor(Anchor anchor) => counter.Anchor = ResultName.Anchor = counter.Origin = ResultName.Origin = anchor; }, true); base.LoadComplete(); From a107fca5d0a774178d8bd3b0fd1ff2725dfeb61b Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Mon, 12 Dec 2022 00:33:28 +0100 Subject: [PATCH 023/376] Hide "Full" option from counter flow directions --- .../Gameplay/TestSceneJudgementCounter.cs | 4 +- .../JudgementCounterDisplay.cs | 39 ++++++++++++++++--- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs index 885b182a6f..1cded54b3e 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs @@ -97,8 +97,8 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestChangeFlowDirection() { - AddStep("Set direction vertical", () => counter.Direction.Value = FillDirection.Vertical); - AddStep("Set direction horizontal", () => counter.Direction.Value = FillDirection.Vertical); + AddStep("Set direction vertical", () => counter.FlowDirection.Value = JudgementCounterDisplay.Flow.Vertical); + AddStep("Set direction horizontal", () => counter.FlowDirection.Value = JudgementCounterDisplay.Flow.Horizonal); } [Test] diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs index b392ce8e04..3ac9e7fc55 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs @@ -19,7 +19,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter public bool UsesFixedAnchor { get; set; } [SettingSource("Counter direction")] - public Bindable Direction { get; set; } = new Bindable(); + public Bindable FlowDirection { get; set; } = new Bindable(); [SettingSource("Show judgement names")] public BindableBool ShowName { get; set; } = new BindableBool(true); @@ -40,7 +40,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter { InternalChild = JudgementContainer = new FillFlowContainer { - Direction = Direction.Value, + Direction = getFlow(FlowDirection.Value), Spacing = new Vector2(10), AutoSizeAxes = Axes.Both }; @@ -61,9 +61,17 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter { base.LoadComplete(); - Direction.BindValueChanged(direction => JudgementContainer.Direction = direction.NewValue); - Mode.BindValueChanged(_ => updateCounter(), true); + FlowDirection.BindValueChanged(direction => + { + JudgementContainer.Direction = getFlow(direction.NewValue); + //Can't pass directly due to Enum conversion + foreach (var counter in JudgementContainer.Children.OfType()) + { + counter.Direction.Value = getFlow(direction.NewValue); + } + }); + Mode.BindValueChanged(_ => updateCounter(), true); ShowMax.BindValueChanged(value => { var firstChild = JudgementContainer.Children.FirstOrDefault(); @@ -113,6 +121,28 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter } } + private FillDirection getFlow(Flow flow) + { + switch (flow) + { + case Flow.Horizonal: + return FillDirection.Horizontal; + + case Flow.Vertical: + return FillDirection.Vertical; + + default: + throw new ArgumentOutOfRangeException(nameof(flow), flow, @"Unsupported direction"); + } + } + + //Used to hide default full option in FillDirection + public enum Flow + { + Horizonal, + Vertical + } + public enum DisplayMode { Simple, @@ -125,7 +155,6 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter JudgementCounter counter = new JudgementCounter(info) { ShowName = { BindTarget = ShowName }, - Direction = { BindTarget = Direction } }; return counter; } From f0c780f1f648860c83584aabf28063f7386b856a Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Mon, 12 Dec 2022 00:48:35 +0100 Subject: [PATCH 024/376] Fix tally header --- osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs index 9cbeea7a2a..e11b09d5a7 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs @@ -1,6 +1,3 @@ - - - // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. From 58bf081096c0c7dbb1ee72cd4de8c7f022db7ca1 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Mon, 12 Dec 2022 10:52:55 +0100 Subject: [PATCH 025/376] Fix judgement counter not loading after first attempt in gameplay, Fix typo in Display --- .../Gameplay/TestSceneJudgementCounter.cs | 2 +- .../JudgementCounterDisplay.cs | 28 ++++++++----------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs index 1cded54b3e..b3e6fefb68 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs @@ -98,7 +98,7 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestChangeFlowDirection() { AddStep("Set direction vertical", () => counter.FlowDirection.Value = JudgementCounterDisplay.Flow.Vertical); - AddStep("Set direction horizontal", () => counter.FlowDirection.Value = JudgementCounterDisplay.Flow.Horizonal); + AddStep("Set direction horizontal", () => counter.FlowDirection.Value = JudgementCounterDisplay.Flow.Horizontal); } [Test] diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs index 3ac9e7fc55..b8e3c97bb5 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs @@ -33,32 +33,28 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter [Resolved] private JudgementTally tally { get; set; } = null!; - protected FillFlowContainer JudgementContainer = null!; + protected FillFlowContainer JudgementContainer; - [BackgroundDependencyLoader] - private void load() + public JudgementCounterDisplay() { + AutoSizeAxes = Axes.Both; InternalChild = JudgementContainer = new FillFlowContainer { Direction = getFlow(FlowDirection.Value), Spacing = new Vector2(10), AutoSizeAxes = Axes.Both }; - - foreach (var result in tally.Results) - { - JudgementContainer.Add(createCounter(result)); - } - } - - protected override void Update() - { - Size = JudgementContainer.Size; - base.Update(); } protected override void LoadComplete() { + //Adding this in "load" will cause it to not load in properly after the first beatmap attempt. Or after existing and reentering. + //this does not happen in tests, or in the skin editor component preview button. + foreach (var result in tally.Results) + { + JudgementContainer.Add(createCounter(result)); + } + base.LoadComplete(); FlowDirection.BindValueChanged(direction => @@ -125,7 +121,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter { switch (flow) { - case Flow.Horizonal: + case Flow.Horizontal: return FillDirection.Horizontal; case Flow.Vertical: @@ -139,7 +135,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter //Used to hide default full option in FillDirection public enum Flow { - Horizonal, + Horizontal, Vertical } From 4d592184ca585119343806486573497d6c841aec Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Mon, 12 Dec 2022 11:53:07 +0100 Subject: [PATCH 026/376] temp cmt --- .../Visual/Gameplay/TestSceneJudgementCounter.cs | 7 +++++-- .../Play/HUD/JudgementCounter/JudgementCounter.cs | 5 +++-- .../Play/HUD/JudgementCounter/JudgementTally.cs | 11 ++++++++++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs index b3e6fefb68..2e35e012f7 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs @@ -34,13 +34,16 @@ namespace osu.Game.Tests.Visual.Gameplay { var ruleset = CreateRuleset(); + var r = ruleset.CreateBeatmapConverter(Beatmap.Value.Beatmap); + + var n = r.Convert().BeatmapInfo.Ruleset.CreateInstance(); Debug.Assert(ruleset != null); - scoreProcessor = new ScoreProcessor(ruleset); + scoreProcessor = new ScoreProcessor(n); Child = new DependencyProvidingContainer { RelativeSizeAxes = Axes.Both, - CachedDependencies = new (Type, object)[] { (typeof(ScoreProcessor), scoreProcessor), (typeof(Ruleset), ruleset) }, + CachedDependencies = new (Type, object)[] { (typeof(ScoreProcessor), scoreProcessor), (typeof(Ruleset), n) }, Children = new Drawable[] { judgementTally = new JudgementTally(), diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs index d7bb8939e1..16cbfd6c7a 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs @@ -9,6 +9,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.UI; namespace osu.Game.Screens.Play.HUD.JudgementCounter { @@ -29,7 +30,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter private JudgementRollingCounter counter = null!; [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OsuColour colours, DrawableRuleset ruleset) { AutoSizeAxes = Axes.Both; InternalChild = flowContainer = new FillFlowContainer @@ -44,7 +45,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter ResultName = new OsuSpriteText { Font = OsuFont.Numeric.With(size: 8), - Text = Result.ResultInfo.Displayname + Text = ruleset.Ruleset.GetDisplayNameForHitResult(Result.ResultInfo.Type) } } }; diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs index e11b09d5a7..b03f71a579 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs @@ -7,6 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; +using osu.Game.Rulesets; using osu.Game.Rulesets.Scoring; namespace osu.Game.Screens.Play.HUD.JudgementCounter @@ -21,7 +22,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter [BackgroundDependencyLoader] private void load(IBindable working) { - foreach (var result in working.Value.BeatmapInfo.Ruleset.CreateInstance().GetHitResults()) + foreach (var result in getRuleset(working).GetHitResults()) { Results.Add(new JudgementCounterInfo { @@ -31,6 +32,14 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter } } + private Ruleset getRuleset(IBindable working) + { + var ruleset = working.Value.BeatmapInfo.Ruleset.CreateInstance(); + var converter = ruleset.RulesetInfo.CreateInstance().CreateBeatmapConverter(working.Value.Beatmap); + + return converter.CanConvert() ? converter.Convert().BeatmapInfo.Ruleset.CreateInstance() : ruleset; + } + protected override void LoadComplete() { base.LoadComplete(); From 8efe7528e3266d08575cf2985ecfd76647e9949e Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Mon, 12 Dec 2022 15:10:10 +0100 Subject: [PATCH 027/376] change ruleset source to avoid issues with converted beatmaps --- .../Gameplay/TestSceneJudgementCounter.cs | 9 +++------ .../HUD/JudgementCounter/JudgementCounter.cs | 10 +++++----- .../JudgementCounterDisplay.cs | 12 ++++++------ .../JudgementCounter/JudgementCounterInfo.cs | 3 +-- .../HUD/JudgementCounter/JudgementTally.cs | 19 +++++-------------- 5 files changed, 20 insertions(+), 33 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs index 2e35e012f7..7a54f47c46 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs @@ -34,16 +34,13 @@ namespace osu.Game.Tests.Visual.Gameplay { var ruleset = CreateRuleset(); - var r = ruleset.CreateBeatmapConverter(Beatmap.Value.Beatmap); - - var n = r.Convert().BeatmapInfo.Ruleset.CreateInstance(); Debug.Assert(ruleset != null); - scoreProcessor = new ScoreProcessor(n); + scoreProcessor = new ScoreProcessor(ruleset); Child = new DependencyProvidingContainer { RelativeSizeAxes = Axes.Both, - CachedDependencies = new (Type, object)[] { (typeof(ScoreProcessor), scoreProcessor), (typeof(Ruleset), n) }, + CachedDependencies = new (Type, object)[] { (typeof(ScoreProcessor), scoreProcessor), (typeof(Ruleset), ruleset) }, Children = new Drawable[] { judgementTally = new JudgementTally(), @@ -130,7 +127,7 @@ namespace osu.Game.Tests.Visual.Gameplay private int hiddenCount() { - var num = counter.JudgementContainer.Children.OfType().First(child => child.Result.ResultInfo.Type == HitResult.LargeTickHit); + var num = counter.JudgementContainer.Children.OfType().First(child => child.Result.Type == HitResult.LargeTickHit); return num.Result.ResultCount.Value; } diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs index 16cbfd6c7a..a4ebd80e9f 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs @@ -8,8 +8,8 @@ using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Rulesets; using osu.Game.Rulesets.Scoring; -using osu.Game.Rulesets.UI; namespace osu.Game.Screens.Play.HUD.JudgementCounter { @@ -30,7 +30,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter private JudgementRollingCounter counter = null!; [BackgroundDependencyLoader] - private void load(OsuColour colours, DrawableRuleset ruleset) + private void load(OsuColour colours, IBindable ruleset) { AutoSizeAxes = Axes.Both; InternalChild = flowContainer = new FillFlowContainer @@ -45,16 +45,16 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter ResultName = new OsuSpriteText { Font = OsuFont.Numeric.With(size: 8), - Text = ruleset.Ruleset.GetDisplayNameForHitResult(Result.ResultInfo.Type) + Text = ruleset.Value.CreateInstance().GetDisplayNameForHitResult(Result.Type) } } }; - var result = Result.ResultInfo.Type; + var result = Result.Type; if (result.IsBasic()) { - Colour = colours.ForHitResult(Result.ResultInfo.Type); + Colour = colours.ForHitResult(Result.Type); return; } diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs index b8e3c97bb5..bcbf8198fb 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs @@ -48,7 +48,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter protected override void LoadComplete() { - //Adding this in "load" will cause it to not load in properly after the first beatmap attempt. Or after existing and reentering. + //Adding this in "load" will cause the component to not load in properly after the first beatmap attempt. Or after existing and reentering. //this does not happen in tests, or in the skin editor component preview button. foreach (var result in tally.Results) { @@ -66,7 +66,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter { counter.Direction.Value = getFlow(direction.NewValue); } - }); + }, true); Mode.BindValueChanged(_ => updateCounter(), true); ShowMax.BindValueChanged(value => { @@ -89,19 +89,19 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter switch (Mode.Value) { case DisplayMode.Simple: - foreach (var counter in counters.Where(counter => counter.Result.ResultInfo.Type.IsBasic())) + foreach (var counter in counters.Where(counter => counter.Result.Type.IsBasic())) counter.Show(); - foreach (var counter in counters.Where(counter => !counter.Result.ResultInfo.Type.IsBasic())) + foreach (var counter in counters.Where(counter => !counter.Result.Type.IsBasic())) counter.Hide(); break; case DisplayMode.Normal: - foreach (var counter in counters.Where(counter => !counter.Result.ResultInfo.Type.IsBonus())) + foreach (var counter in counters.Where(counter => !counter.Result.Type.IsBonus())) counter.Show(); - foreach (var counter in counters.Where(counter => counter.Result.ResultInfo.Type.IsBonus())) + foreach (var counter in counters.Where(counter => counter.Result.Type.IsBonus())) counter.Hide(); break; diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterInfo.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterInfo.cs index 45f89c30d2..0237981db1 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterInfo.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterInfo.cs @@ -2,14 +2,13 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Bindables; -using osu.Framework.Localisation; using osu.Game.Rulesets.Scoring; namespace osu.Game.Screens.Play.HUD.JudgementCounter { public struct JudgementCounterInfo { - public (HitResult Type, LocalisableString Displayname) ResultInfo { get; set; } + public HitResult Type { get; set; } public BindableInt ResultCount { get; set; } } diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs index b03f71a579..a88b18ff6f 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs @@ -6,7 +6,6 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Containers; -using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Rulesets.Scoring; @@ -20,39 +19,31 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter public List Results = new List(); [BackgroundDependencyLoader] - private void load(IBindable working) + private void load(IBindable ruleset) { - foreach (var result in getRuleset(working).GetHitResults()) + foreach (var result in ruleset.Value.CreateInstance().GetHitResults()) { Results.Add(new JudgementCounterInfo { - ResultInfo = (result.result, result.displayName), + Type = result.result, ResultCount = new BindableInt() }); } } - private Ruleset getRuleset(IBindable working) - { - var ruleset = working.Value.BeatmapInfo.Ruleset.CreateInstance(); - var converter = ruleset.RulesetInfo.CreateInstance().CreateBeatmapConverter(working.Value.Beatmap); - - return converter.CanConvert() ? converter.Convert().BeatmapInfo.Ruleset.CreateInstance() : ruleset; - } - protected override void LoadComplete() { base.LoadComplete(); scoreProcessor.NewJudgement += judgement => { - foreach (JudgementCounterInfo result in Results.Where(result => result.ResultInfo.Type == judgement.Type)) + foreach (JudgementCounterInfo result in Results.Where(result => result.Type == judgement.Type)) { result.ResultCount.Value++; } }; scoreProcessor.JudgementReverted += judgement => { - foreach (JudgementCounterInfo result in Results.Where(result => result.ResultInfo.Type == judgement.Type)) + foreach (JudgementCounterInfo result in Results.Where(result => result.Type == judgement.Type)) { result.ResultCount.Value--; } From 99d83315c11a946472f9dbeb001f55ad74970b2f Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Mon, 12 Dec 2022 15:10:45 +0100 Subject: [PATCH 028/376] change settings order --- .../Play/HUD/JudgementCounter/JudgementCounterDisplay.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs index bcbf8198fb..4880314f29 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs @@ -18,6 +18,9 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter { public bool UsesFixedAnchor { get; set; } + [SettingSource("Display mode")] + public Bindable Mode { get; set; } = new Bindable(); + [SettingSource("Counter direction")] public Bindable FlowDirection { get; set; } = new Bindable(); @@ -27,9 +30,6 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter [SettingSource("Show max judgement")] public BindableBool ShowMax { get; set; } = new BindableBool(true); - [SettingSource("Display mode")] - public Bindable Mode { get; set; } = new Bindable(); - [Resolved] private JudgementTally tally { get; set; } = null!; From edb46e422c20983ae9599a394244c01787282806 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Mon, 12 Dec 2022 15:15:30 +0100 Subject: [PATCH 029/376] Fix "using" name in HUD overlay --- osu.Game/Screens/Play/HUDOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 816b8b2543..89d02e5fb0 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -24,7 +24,7 @@ using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Play.HUD.ClicksPerSecond; using osu.Game.Skinning; using osuTK; -using JudgementTally = osu.Game.Screens.Play.HUD.JudgementCounter.JudgementTally; +using osu.Game.Screens.Play.HUD.JudgementCounter; namespace osu.Game.Screens.Play { From 9a235b32133e45827f71533cd86e799ca66155bb Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Wed, 14 Dec 2022 23:00:34 +0100 Subject: [PATCH 030/376] remove rolling duration, fix issue with loading --- .../Play/HUD/JudgementCounter/JudgementCounter.cs | 2 -- .../HUD/JudgementCounter/JudgementCounterDisplay.cs | 13 ++++++------- .../Play/HUD/JudgementCounter/JudgementTally.cs | 6 ++---- osu.Game/Screens/Play/HUDOverlay.cs | 3 ++- 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs index a4ebd80e9f..3f7dbefcd1 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs @@ -112,8 +112,6 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter { protected override OsuSpriteText CreateSpriteText() => base.CreateSpriteText().With(s => s.Font = s.Font.With(fixedWidth: true, size: 16)); - - protected override double RollingDuration => 750; } } } diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs index 4880314f29..36466fa8a9 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs @@ -33,9 +33,10 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter [Resolved] private JudgementTally tally { get; set; } = null!; - protected FillFlowContainer JudgementContainer; + protected FillFlowContainer JudgementContainer = null!; - public JudgementCounterDisplay() + [BackgroundDependencyLoader] + private void load() { AutoSizeAxes = Axes.Both; InternalChild = JudgementContainer = new FillFlowContainer @@ -44,17 +45,15 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter Spacing = new Vector2(10), AutoSizeAxes = Axes.Both }; - } - protected override void LoadComplete() - { - //Adding this in "load" will cause the component to not load in properly after the first beatmap attempt. Or after existing and reentering. - //this does not happen in tests, or in the skin editor component preview button. foreach (var result in tally.Results) { JudgementContainer.Add(createCounter(result)); } + } + protected override void LoadComplete() + { base.LoadComplete(); FlowDirection.BindValueChanged(direction => diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs index a88b18ff6f..e6bc336b0b 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs @@ -34,19 +34,17 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter protected override void LoadComplete() { base.LoadComplete(); + scoreProcessor.NewJudgement += judgement => { foreach (JudgementCounterInfo result in Results.Where(result => result.Type == judgement.Type)) - { result.ResultCount.Value++; - } }; + scoreProcessor.JudgementReverted += judgement => { foreach (JudgementCounterInfo result in Results.Where(result => result.Type == judgement.Type)) - { result.ResultCount.Value--; - } }; } } diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 89d02e5fb0..728da22123 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -107,6 +107,8 @@ namespace osu.Game.Screens.Play Children = new Drawable[] { CreateFailingLayer(), + //Needs to be initialized before skinnable drawables. + tally = new JudgementTally(), mainComponents = new MainComponentsContainer { AlwaysPresent = true, @@ -150,7 +152,6 @@ namespace osu.Game.Screens.Play Spacing = new Vector2(5) }, clicksPerSecondCalculator = new ClicksPerSecondCalculator(), - tally = new JudgementTally() }; hideTargets = new List { mainComponents, KeyCounter, topRightElements }; From 0c177aa7dedb51352da4de6f5fd1d239a51a8331 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 15 Dec 2022 16:12:34 +0100 Subject: [PATCH 031/376] Improve tests, simplify "updateDisplay" method --- .../Gameplay/TestSceneJudgementCounter.cs | 38 ++++++++------ .../HUD/JudgementCounter/JudgementCounter.cs | 2 +- .../JudgementCounterDisplay.cs | 50 +++++++++---------- 3 files changed, 47 insertions(+), 43 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs index 7a54f47c46..1d79d8e408 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs @@ -23,7 +23,7 @@ namespace osu.Game.Tests.Visual.Gameplay { private ScoreProcessor scoreProcessor = null!; private JudgementTally judgementTally = null!; - private TestJudgementCounterDisplay counter = null!; + private TestJudgementCounterDisplay counterDisplay = null!; private readonly Bindable lastJudgementResult = new Bindable(); @@ -48,7 +48,7 @@ namespace osu.Game.Tests.Visual.Gameplay { RelativeSizeAxes = Axes.Both, CachedDependencies = new (Type, object)[] { (typeof(JudgementTally), judgementTally) }, - Child = counter = new TestJudgementCounterDisplay + Child = counterDisplay = new TestJudgementCounterDisplay { Margin = new MarginPadding { Top = 100 }, Anchor = Anchor.TopCentre, @@ -82,7 +82,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddRepeatStep("Add judgement", () => applyOneJudgement(HitResult.Miss), 2); AddRepeatStep("Add judgement", () => applyOneJudgement(HitResult.Meh), 2); AddRepeatStep("Add judgement", () => applyOneJudgement(HitResult.LargeTickHit), 2); - AddStep("Show all judgements", () => counter.Mode.Value = JudgementCounterDisplay.DisplayMode.All); + AddStep("Show all judgements", () => counterDisplay.Mode.Value = JudgementCounterDisplay.DisplayMode.All); AddAssert("Check value added whilst hidden", () => hiddenCount() == 2); } @@ -91,43 +91,49 @@ namespace osu.Game.Tests.Visual.Gameplay { AddRepeatStep("Add judgement", () => applyOneJudgement(HitResult.LargeTickHit), 2); AddAssert("Check value added whilst hidden", () => hiddenCount() == 2); - AddStep("Show all judgements", () => counter.Mode.Value = JudgementCounterDisplay.DisplayMode.All); + AddStep("Show all judgements", () => counterDisplay.Mode.Value = JudgementCounterDisplay.DisplayMode.All); } [Test] public void TestChangeFlowDirection() { - AddStep("Set direction vertical", () => counter.FlowDirection.Value = JudgementCounterDisplay.Flow.Vertical); - AddStep("Set direction horizontal", () => counter.FlowDirection.Value = JudgementCounterDisplay.Flow.Horizontal); + AddStep("Set direction vertical", () => counterDisplay.FlowDirection.Value = JudgementCounterDisplay.Flow.Vertical); + AddStep("Set direction horizontal", () => counterDisplay.FlowDirection.Value = JudgementCounterDisplay.Flow.Horizontal); } [Test] public void TestToggleJudgementNames() { - AddStep("Hide judgement names", () => counter.ShowName.Value = false); - AddAssert("Assert hidden", () => counter.JudgementContainer.Children.OfType().First().ResultName.Alpha == 0); - AddStep("Hide judgement names", () => counter.ShowName.Value = true); - AddAssert("Assert shown", () => counter.JudgementContainer.Children.OfType().First().ResultName.Alpha == 1); + AddStep("Hide judgement names", () => counterDisplay.ShowName.Value = false); + AddAssert("Assert hidden", () => counterDisplay.JudgementContainer.Children.OfType().First().ResultName.Alpha == 0); + AddStep("Hide judgement names", () => counterDisplay.ShowName.Value = true); + AddAssert("Assert shown", () => counterDisplay.JudgementContainer.Children.OfType().First().ResultName.Alpha == 1); } [Test] public void TestHideMaxValue() { - AddStep("Hide max judgement", () => counter.ShowMax.Value = false); - AddStep("Show max judgement", () => counter.ShowMax.Value = true); + AddStep("Hide max judgement", () => counterDisplay.ShowMax.Value = false); + AddWaitStep("wait some", 2); + AddAssert("Check max hidden", () => counterDisplay.JudgementContainer.ChildrenOfType().First().Alpha == 0); + AddStep("Show max judgement", () => counterDisplay.ShowMax.Value = true); } [Test] public void TestCycleDisplayModes() { - AddStep("Show all judgements", () => counter.Mode.Value = JudgementCounterDisplay.DisplayMode.All); - AddStep("Show normal judgements", () => counter.Mode.Value = JudgementCounterDisplay.DisplayMode.Normal); - AddStep("Show basic judgements", () => counter.Mode.Value = JudgementCounterDisplay.DisplayMode.Simple); + AddStep("Show basic judgements", () => counterDisplay.Mode.Value = JudgementCounterDisplay.DisplayMode.Simple); + AddWaitStep("wait some", 2); + AddAssert("Check only basic", () => counterDisplay.JudgementContainer.ChildrenOfType().Last().Alpha == 0); + AddStep("Show normal judgements", () => counterDisplay.Mode.Value = JudgementCounterDisplay.DisplayMode.Normal); + AddStep("Show all judgements", () => counterDisplay.Mode.Value = JudgementCounterDisplay.DisplayMode.All); + AddWaitStep("wait some", 2); + AddAssert("Check all visible", () => counterDisplay.JudgementContainer.ChildrenOfType().Last().Alpha == 1); } private int hiddenCount() { - var num = counter.JudgementContainer.Children.OfType().First(child => child.Result.Type == HitResult.LargeTickHit); + var num = counterDisplay.JudgementContainer.Children.OfType().First(child => child.Result.Type == HitResult.LargeTickHit); return num.Result.ResultCount.Value; } diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs index 3f7dbefcd1..efb4c532f9 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs @@ -100,7 +100,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter protected override void PopIn() { - this.FadeInFromZero(500, Easing.OutQuint); + this.FadeIn(500, Easing.OutQuint); } protected override void PopOut() diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs index 36466fa8a9..1842ba1eae 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs @@ -66,7 +66,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter counter.Direction.Value = getFlow(direction.NewValue); } }, true); - Mode.BindValueChanged(_ => updateCounter(), true); + Mode.BindValueChanged(_ => updateMode(), true); ShowMax.BindValueChanged(value => { var firstChild = JudgementContainer.Children.FirstOrDefault(); @@ -81,38 +81,35 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter }, true); } - private void updateCounter() + private void updateMode() { - var counters = JudgementContainer.Children.OfType().ToList(); - - switch (Mode.Value) + foreach (var counter in JudgementContainer.Children.OfType().Where(counter => !counter.Result.Type.IsBasic())) { - case DisplayMode.Simple: - foreach (var counter in counters.Where(counter => counter.Result.Type.IsBasic())) - counter.Show(); - - foreach (var counter in counters.Where(counter => !counter.Result.Type.IsBasic())) + switch (Mode.Value) + { + case DisplayMode.Simple: counter.Hide(); - break; + break; - case DisplayMode.Normal: - foreach (var counter in counters.Where(counter => !counter.Result.Type.IsBonus())) + case DisplayMode.Normal: + if (counter.Result.Type.IsBonus()) + { + counter.Hide(); + break; + } + + counter.Show(); + break; + + case DisplayMode.All: counter.Show(); - foreach (var counter in counters.Where(counter => counter.Result.Type.IsBonus())) - counter.Hide(); + break; - break; - - case DisplayMode.All: - foreach (JudgementCounter counter in counters.Where(counter => !counter.IsPresent)) - counter.Show(); - - break; - - default: - throw new ArgumentOutOfRangeException(); + default: + throw new ArgumentOutOfRangeException(); + } } } @@ -149,7 +146,8 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter { JudgementCounter counter = new JudgementCounter(info) { - ShowName = { BindTarget = ShowName }, + State = { Value = Visibility.Visible }, + ShowName = { BindTarget = ShowName } }; return counter; } From f3873b73e3290d338cc3e1348e3588a23d242c47 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Fri, 16 Dec 2022 17:40:39 +0100 Subject: [PATCH 032/376] Clean up syntax for readability --- .../Gameplay/TestSceneJudgementCounter.cs | 5 +- .../HUD/JudgementCounter/JudgementCounter.cs | 49 +++---------------- .../JudgementCounterDisplay.cs | 24 ++------- .../HUD/JudgementCounter/JudgementTally.cs | 18 +++---- 4 files changed, 19 insertions(+), 77 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs index 1d79d8e408..a8d9f203ae 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs @@ -81,9 +81,6 @@ namespace osu.Game.Tests.Visual.Gameplay AddRepeatStep("Add judgement", () => applyOneJudgement(HitResult.Great), 2); AddRepeatStep("Add judgement", () => applyOneJudgement(HitResult.Miss), 2); AddRepeatStep("Add judgement", () => applyOneJudgement(HitResult.Meh), 2); - AddRepeatStep("Add judgement", () => applyOneJudgement(HitResult.LargeTickHit), 2); - AddStep("Show all judgements", () => counterDisplay.Mode.Value = JudgementCounterDisplay.DisplayMode.All); - AddAssert("Check value added whilst hidden", () => hiddenCount() == 2); } [Test] @@ -105,8 +102,10 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestToggleJudgementNames() { AddStep("Hide judgement names", () => counterDisplay.ShowName.Value = false); + AddWaitStep("wait some", 2); AddAssert("Assert hidden", () => counterDisplay.JudgementContainer.Children.OfType().First().ResultName.Alpha == 0); AddStep("Hide judgement names", () => counterDisplay.ShowName.Value = true); + AddWaitStep("wait some", 2); AddAssert("Assert shown", () => counterDisplay.JudgementContainer.Children.OfType().First().ResultName.Alpha == 1); } diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs index efb4c532f9..ea6e9997e3 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs @@ -20,10 +20,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter public readonly JudgementCounterInfo Result; - public JudgementCounter(JudgementCounterInfo result) - { - Result = result; - } + public JudgementCounter(JudgementCounterInfo result) => Result = result; public OsuSpriteText ResultName = null!; private FillFlowContainer flowContainer = null!; @@ -52,45 +49,18 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter var result = Result.Type; - if (result.IsBasic()) - { - Colour = colours.ForHitResult(Result.Type); - return; - } - - if (!result.IsBonus()) - { - Colour = colours.PurpleLight; - return; - } - - Colour = colours.PurpleLighter; + Colour = result.IsBasic() ? colours.ForHitResult(Result.Type) : !result.IsBonus() ? colours.PurpleLight : colours.PurpleLighter; } protected override void LoadComplete() { ShowName.BindValueChanged(value => - { - if (value.NewValue) - { - ResultName.Show(); - return; - } - - ResultName.Hide(); - }, true); + ResultName.FadeTo(value.NewValue ? 1 : 0, JudgementCounterDisplay.TRANSFORM_DURATION, Easing.OutQuint), true); Direction.BindValueChanged(direction => { flowContainer.Direction = direction.NewValue; - - if (direction.NewValue == FillDirection.Vertical) - { - changeAnchor(Anchor.TopLeft); - return; - } - - changeAnchor(Anchor.BottomLeft); + changeAnchor(direction.NewValue == FillDirection.Vertical ? Anchor.TopLeft : Anchor.BottomLeft); void changeAnchor(Anchor anchor) => counter.Anchor = ResultName.Anchor = counter.Origin = ResultName.Origin = anchor; }, true); @@ -98,15 +68,8 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter base.LoadComplete(); } - protected override void PopIn() - { - this.FadeIn(500, Easing.OutQuint); - } - - protected override void PopOut() - { - this.FadeOut(100); - } + protected override void PopIn() => this.FadeIn(JudgementCounterDisplay.TRANSFORM_DURATION, Easing.OutQuint); + protected override void PopOut() => this.FadeOut(100); private sealed partial class JudgementRollingCounter : RollingCounter { diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs index 1842ba1eae..4e2b2a10cd 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs @@ -16,6 +16,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter { public partial class JudgementCounterDisplay : CompositeDrawable, ISkinnableDrawable { + public const int TRANSFORM_DURATION = 500; public bool UsesFixedAnchor { get; set; } [SettingSource("Display mode")] @@ -47,9 +48,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter }; foreach (var result in tally.Results) - { JudgementContainer.Add(createCounter(result)); - } } protected override void LoadComplete() @@ -62,22 +61,13 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter //Can't pass directly due to Enum conversion foreach (var counter in JudgementContainer.Children.OfType()) - { counter.Direction.Value = getFlow(direction.NewValue); - } }, true); Mode.BindValueChanged(_ => updateMode(), true); ShowMax.BindValueChanged(value => { var firstChild = JudgementContainer.Children.FirstOrDefault(); - - if (value.NewValue) - { - firstChild?.Show(); - return; - } - - firstChild?.Hide(); + firstChild.FadeTo(value.NewValue ? 1 : 0, TRANSFORM_DURATION, Easing.OutQuint); }, true); } @@ -89,22 +79,14 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter { case DisplayMode.Simple: counter.Hide(); - break; case DisplayMode.Normal: - if (counter.Result.Type.IsBonus()) - { - counter.Hide(); - break; - } - - counter.Show(); + counter.FadeTo(counter.Result.Type.IsBonus() ? 0 : 1); break; case DisplayMode.All: counter.Show(); - break; default: diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs index e6bc336b0b..d8eac309aa 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs @@ -7,6 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets; +using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; namespace osu.Game.Screens.Play.HUD.JudgementCounter @@ -35,17 +36,14 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter { base.LoadComplete(); - scoreProcessor.NewJudgement += judgement => - { - foreach (JudgementCounterInfo result in Results.Where(result => result.Type == judgement.Type)) - result.ResultCount.Value++; - }; + scoreProcessor.NewJudgement += judgement => updateCount(judgement, false); + scoreProcessor.JudgementReverted += judgement => updateCount(judgement, true); + } - scoreProcessor.JudgementReverted += judgement => - { - foreach (JudgementCounterInfo result in Results.Where(result => result.Type == judgement.Type)) - result.ResultCount.Value--; - }; + private void updateCount(JudgementResult judgement, bool revert) + { + foreach (JudgementCounterInfo result in Results.Where(result => result.Type == judgement.Type)) + result.ResultCount.Value = revert ? result.ResultCount.Value - 1 : result.ResultCount.Value + 1; } } } From c200e7799418a2ca7c83b3e7f821918227eec845 Mon Sep 17 00:00:00 2001 From: Dylan Nantz Date: Mon, 19 Dec 2022 18:31:28 -0500 Subject: [PATCH 033/376] Add mania hidden mod configuration --- .../Mods/TestSceneManiaModHidden.cs | 19 +++++++++++++++++++ .../Mods/ManiaModHidden.cs | 12 ++++++++++++ .../Mods/ManiaModPlayfieldCover.cs | 4 +++- 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHidden.cs diff --git a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHidden.cs b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHidden.cs new file mode 100644 index 0000000000..65ee43dfaf --- /dev/null +++ b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHidden.cs @@ -0,0 +1,19 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Game.Rulesets.Mania.Mods; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Mania.Tests.Mods +{ + public partial class TestSceneManiaModHidden : ModTestScene + { + protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset(); + + [TestCase(0.5f)] + [TestCase(0.2f)] + [TestCase(0.8f)] + public void TestCoverage(float Coverage) => CreateModTest(new ModTestData { Mod = new ManiaModHidden { CoverageAmount = { Value = Coverage } }, PassCondition = () => true }); + } +} diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs index eeb6e94fc7..5dcb859f7a 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs @@ -4,7 +4,9 @@ using System; using System.Linq; using osu.Framework.Localisation; +using osu.Game.Configuration; using osu.Game.Rulesets.Mania.UI; +using osu.Framework.Bindables; namespace osu.Game.Rulesets.Mania.Mods { @@ -13,6 +15,16 @@ namespace osu.Game.Rulesets.Mania.Mods public override LocalisableString Description => @"Keys fade out before you hit them!"; public override double ScoreMultiplier => 1; + [SettingSource("Coverage", "How much of the playfield notes should be hidden for.")] + public BindableNumber CoverageAmount { get; } = new BindableFloat(0.5f) + { + Precision = 0.01f, + MinValue = 0.2f, + MaxValue = 0.8f, + Default = 0.5f, + }; + public override float Coverage => CoverageAmount.Value; + public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ManiaModFadeIn)).ToArray(); protected override CoverExpandDirection ExpandDirection => CoverExpandDirection.AgainstScroll; diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs index 6a94e5d371..635ad1f2e8 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs @@ -22,6 +22,8 @@ namespace osu.Game.Rulesets.Mania.Mods /// protected abstract CoverExpandDirection ExpandDirection { get; } + public virtual float Coverage {get => 0.5f;} + public virtual void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { ManiaPlayfield maniaPlayfield = (ManiaPlayfield)drawableRuleset.Playfield; @@ -36,7 +38,7 @@ namespace osu.Game.Rulesets.Mania.Mods { c.RelativeSizeAxes = Axes.Both; c.Direction = ExpandDirection; - c.Coverage = 0.5f; + c.Coverage = Coverage; })); } } From 42dbb0bfd077bfa0240f81193a302d884018cbd2 Mon Sep 17 00:00:00 2001 From: Dylan Nantz Date: Mon, 19 Dec 2022 19:24:38 -0500 Subject: [PATCH 034/376] fix formatting --- osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs index 635ad1f2e8..5e9c1a4ae7 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Mania.Mods /// protected abstract CoverExpandDirection ExpandDirection { get; } - public virtual float Coverage {get => 0.5f;} + public virtual float Coverage { get => 0.5f; } public virtual void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { From 4a1a023f9e7ca7a68841f1558cfa55dcb3a25cee Mon Sep 17 00:00:00 2001 From: Dylan Nantz Date: Tue, 20 Dec 2022 13:33:33 -0500 Subject: [PATCH 035/376] Code quality improvements --- .../Mods/TestSceneManiaModHidden.cs | 2 +- osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs | 5 +++-- osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHidden.cs b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHidden.cs index 65ee43dfaf..44d206d9e1 100644 --- a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHidden.cs +++ b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHidden.cs @@ -14,6 +14,6 @@ namespace osu.Game.Rulesets.Mania.Tests.Mods [TestCase(0.5f)] [TestCase(0.2f)] [TestCase(0.8f)] - public void TestCoverage(float Coverage) => CreateModTest(new ModTestData { Mod = new ManiaModHidden { CoverageAmount = { Value = Coverage } }, PassCondition = () => true }); + public void TestCoverage(float coverage) => CreateModTest(new ModTestData { Mod = new ManiaModHidden { CoverageAmount = { Value = coverage } }, PassCondition = () => true }); } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs index 5dcb859f7a..76a102bda3 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Mods public override LocalisableString Description => @"Keys fade out before you hit them!"; public override double ScoreMultiplier => 1; - [SettingSource("Coverage", "How much of the playfield notes should be hidden for.")] + [SettingSource("Coverage", "The proportion of playfield height that notes will be hidden for.")] public BindableNumber CoverageAmount { get; } = new BindableFloat(0.5f) { Precision = 0.01f, @@ -23,7 +23,8 @@ namespace osu.Game.Rulesets.Mania.Mods MaxValue = 0.8f, Default = 0.5f, }; - public override float Coverage => CoverageAmount.Value; + + protected override float Coverage => CoverageAmount.Value; public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ManiaModFadeIn)).ToArray(); diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs index 5e9c1a4ae7..bfb70938b9 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Mania.Mods /// protected abstract CoverExpandDirection ExpandDirection { get; } - public virtual float Coverage { get => 0.5f; } + protected virtual float Coverage => 0.5f; public virtual void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { From a0690e7ffb1bb1f2ea81ea65090a4b0b890b619b Mon Sep 17 00:00:00 2001 From: integer <7279624+integerrr@users.noreply.github.com> Date: Mon, 26 Dec 2022 22:23:31 +0000 Subject: [PATCH 036/376] replay menus remembers expanded state no messing with readonly fields --- .../NonVisual/SessionStaticsTest.cs | 6 ++++++ osu.Game/Configuration/SessionStatics.cs | 4 ++++ .../Screens/Play/HUD/PlayerSettingsOverlay.cs | 19 ++++++++++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/NonVisual/SessionStaticsTest.cs b/osu.Game.Tests/NonVisual/SessionStaticsTest.cs index 5c8254b947..499c0e5d34 100644 --- a/osu.Game.Tests/NonVisual/SessionStaticsTest.cs +++ b/osu.Game.Tests/NonVisual/SessionStaticsTest.cs @@ -24,12 +24,16 @@ namespace osu.Game.Tests.NonVisual sessionStatics.SetValue(Static.MutedAudioNotificationShownOnce, true); sessionStatics.SetValue(Static.LowBatteryNotificationShownOnce, true); sessionStatics.SetValue(Static.LastHoverSoundPlaybackTime, (double?)1d); + sessionStatics.SetValue(Static.ReplayPlaybackSettingExpanded, false); + sessionStatics.SetValue(Static.ReplayVisualSettingsExpanded, true); sessionStatics.SetValue(Static.SeasonalBackgrounds, new APISeasonalBackgrounds { EndDate = new DateTimeOffset(2022, 1, 1, 0, 0, 0, TimeSpan.Zero) }); Assert.IsFalse(sessionStatics.GetBindable(Static.LoginOverlayDisplayed).IsDefault); Assert.IsFalse(sessionStatics.GetBindable(Static.MutedAudioNotificationShownOnce).IsDefault); Assert.IsFalse(sessionStatics.GetBindable(Static.LowBatteryNotificationShownOnce).IsDefault); Assert.IsFalse(sessionStatics.GetBindable(Static.LastHoverSoundPlaybackTime).IsDefault); + Assert.IsFalse(sessionStatics.GetBindable(Static.ReplayPlaybackSettingExpanded).IsDefault); + Assert.IsFalse(sessionStatics.GetBindable(Static.ReplayVisualSettingsExpanded).IsDefault); Assert.IsFalse(sessionStatics.GetBindable(Static.SeasonalBackgrounds).IsDefault); sessionStatics.ResetAfterInactivity(); @@ -39,6 +43,8 @@ namespace osu.Game.Tests.NonVisual Assert.IsTrue(sessionStatics.GetBindable(Static.LowBatteryNotificationShownOnce).IsDefault); // some statics should not reset despite inactivity. Assert.IsFalse(sessionStatics.GetBindable(Static.LastHoverSoundPlaybackTime).IsDefault); + Assert.IsFalse(sessionStatics.GetBindable(Static.ReplayPlaybackSettingExpanded).IsDefault); + Assert.IsFalse(sessionStatics.GetBindable(Static.ReplayVisualSettingsExpanded).IsDefault); Assert.IsFalse(sessionStatics.GetBindable(Static.SeasonalBackgrounds).IsDefault); } } diff --git a/osu.Game/Configuration/SessionStatics.cs b/osu.Game/Configuration/SessionStatics.cs index 12a30a0c84..f08658f182 100644 --- a/osu.Game/Configuration/SessionStatics.cs +++ b/osu.Game/Configuration/SessionStatics.cs @@ -20,6 +20,8 @@ namespace osu.Game.Configuration SetDefault(Static.MutedAudioNotificationShownOnce, false); SetDefault(Static.LowBatteryNotificationShownOnce, false); SetDefault(Static.LastHoverSoundPlaybackTime, (double?)null); + SetDefault(Static.ReplayPlaybackSettingExpanded, true); + SetDefault(Static.ReplayVisualSettingsExpanded, false); SetDefault(Static.SeasonalBackgrounds, null); } @@ -42,6 +44,8 @@ namespace osu.Game.Configuration LoginOverlayDisplayed, MutedAudioNotificationShownOnce, LowBatteryNotificationShownOnce, + ReplayPlaybackSettingExpanded, + ReplayVisualSettingsExpanded, /// /// Info about seasonal backgrounds available fetched from API - see . diff --git a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs index 5f6f040959..c4f07f77cd 100644 --- a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs +++ b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs @@ -3,12 +3,15 @@ #nullable disable +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; using osuTK; using osu.Game.Screens.Play.PlayerSettings; using osuTK.Input; +using osu.Game.Configuration; +using osu.Framework.Allocation; namespace osu.Game.Screens.Play.HUD { @@ -16,6 +19,10 @@ namespace osu.Game.Screens.Play.HUD { private const int fade_duration = 200; + private Bindable playbackMenuExpanded; + + private Bindable visualMenuExpanded; + public bool ReplayLoaded; public readonly PlaybackSettings PlaybackSettings; @@ -42,11 +49,21 @@ namespace osu.Game.Screens.Play.HUD //CollectionSettings = new CollectionSettings(), //DiscussionSettings = new DiscussionSettings(), PlaybackSettings = new PlaybackSettings(), - VisualSettings = new VisualSettings { Expanded = { Value = false } } + VisualSettings = new VisualSettings() } }; } + [BackgroundDependencyLoader] + private void load(SessionStatics statics) + { + playbackMenuExpanded = statics.GetBindable(Static.ReplayPlaybackSettingExpanded); + visualMenuExpanded = statics.GetBindable(Static.ReplayVisualSettingsExpanded); + + PlaybackSettings.Expanded.BindTo(playbackMenuExpanded); + VisualSettings.Expanded.BindTo(visualMenuExpanded); + } + protected override void PopIn() => this.FadeIn(fade_duration); protected override void PopOut() => this.FadeOut(fade_duration); From 39221a52dacdc4232f071ab03cac9c70aea8ada6 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 5 Jan 2023 12:49:45 +0300 Subject: [PATCH 037/376] 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 038/376] 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 b8fbd68e325018606a5b2de181c0d64a7f0a9c16 Mon Sep 17 00:00:00 2001 From: Dylan Nantz Date: Fri, 6 Jan 2023 11:39:41 -0500 Subject: [PATCH 039/376] reduce mania hidden mod precision --- osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs index 76a102bda3..2eb9e6d1eb 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Mania.Mods [SettingSource("Coverage", "The proportion of playfield height that notes will be hidden for.")] public BindableNumber CoverageAmount { get; } = new BindableFloat(0.5f) { - Precision = 0.01f, + Precision = 0.1f, MinValue = 0.2f, MaxValue = 0.8f, Default = 0.5f, From 768a33bb64a5fef23201c5224bd53336eb80e133 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Fri, 6 Jan 2023 23:31:19 +0300 Subject: [PATCH 040/376] Add request class --- .../Online/API/Requests/CommentPostRequest.cs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 osu.Game/Online/API/Requests/CommentPostRequest.cs diff --git a/osu.Game/Online/API/Requests/CommentPostRequest.cs b/osu.Game/Online/API/Requests/CommentPostRequest.cs new file mode 100644 index 0000000000..bd69c04bed --- /dev/null +++ b/osu.Game/Online/API/Requests/CommentPostRequest.cs @@ -0,0 +1,41 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Net.Http; +using osu.Framework.IO.Network; +using osu.Game.Online.API.Requests.Responses; + +namespace osu.Game.Online.API.Requests +{ + public class CommentPostRequest : APIRequest + { + public readonly CommentableType Commentable; + public readonly long CommentableId; + public readonly string Message; + public readonly long? ReplyTo; + + public CommentPostRequest(CommentableType commentable, long commentableId, string message, long? replyTo = null) + { + Commentable = commentable; + CommentableId = commentableId; + Message = message; + ReplyTo = replyTo; + } + + protected override WebRequest CreateWebRequest() + { + var req = base.CreateWebRequest(); + req.Method = HttpMethod.Post; + + req.AddParameter(@"comment[commentable_type]", Commentable.ToString()); + req.AddParameter(@"comment[commentable_id]", $"{CommentableId}"); + req.AddParameter(@"comment[message]", Message); + if (ReplyTo.HasValue) + req.AddParameter(@"comment[parent_id]", $"{ReplyTo}"); + + return req; + } + + protected override string Target => "comments"; + } +} From 32e90829e3d0b2df4241ecf9f419446a4d42d587 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 7 Jan 2023 02:59:24 +0300 Subject: [PATCH 041/376] Integrate comment editor into container --- .../Overlays/Comments/CommentsContainer.cs | 68 ++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 7bd2d6a5e6..c8a2ab39ae 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -17,15 +17,23 @@ using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Threading; using System.Collections.Generic; using JetBrains.Annotations; +using osu.Framework.Localisation; using osu.Game.Graphics.Sprites; using osu.Game.Resources.Localisation.Web; -using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; +using osu.Game.Users.Drawables; +using osuTK; namespace osu.Game.Overlays.Comments { + [Cached] public partial class CommentsContainer : CompositeDrawable { + private const string cid = "commentableId"; + + [Cached] private readonly Bindable type = new Bindable(); + + [Cached(name: cid)] private readonly BindableLong id = new BindableLong(); public readonly Bindable Sort = new Bindable(); @@ -46,12 +54,14 @@ namespace osu.Game.Overlays.Comments private DeletedCommentsCounter deletedCommentsCounter; private CommentsShowMoreButton moreButton; private TotalCommentsCounter commentCounter; + private UpdateableAvatar avatar; [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; + AddRangeInternal(new Drawable[] { new Box @@ -86,6 +96,29 @@ namespace osu.Game.Overlays.Comments }, }, }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Horizontal = 50, Vertical = 20 }, + Children = new Drawable[] + { + avatar = new UpdateableAvatar(api.LocalUser.Value) + { + Size = new Vector2(50), + CornerExponent = 2, + CornerRadius = 25, + Masking = true, + }, + new Container + { + Padding = new MarginPadding { Left = 60 }, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Child = new NewCommentEditor() + } + } + }, new CommentsHeader { Sort = { BindTarget = Sort }, @@ -146,6 +179,7 @@ namespace osu.Game.Overlays.Comments }); User.BindTo(api.LocalUser); + User.BindValueChanged(e => avatar.User = e.NewValue); } protected override void LoadComplete() @@ -336,5 +370,37 @@ namespace osu.Game.Overlays.Comments }); } } + + private partial class NewCommentEditor : CommentEditor + { + [Resolved] + public Bindable CommentableType { get; set; } + + [Resolved(name: cid)] + public BindableLong CommentableId { get; set; } + + protected override LocalisableString FooterText => default; + protected override LocalisableString CommitButtonText => CommonStrings.ButtonsPost; + protected override LocalisableString TextBoxPlaceholder => CommentsStrings.PlaceholderNew; + + [Resolved] + private IAPIProvider api { get; set; } + + protected override void OnCommit(string text) + { + CommitButton.IsLoadingSpinnerShown = true; + CommentPostRequest req = new CommentPostRequest(CommentableType.Value, CommentableId.Value, text); + req.Failure += _ => Schedule(() => + { + CommitButton.IsLoadingSpinnerShown = false; + }); + req.Success += cb => Schedule(() => + { + CommitButton.IsLoadingSpinnerShown = false; + Current.Value = string.Empty; + }); + api.Queue(req); + } + } } } From 58bf7349eea9cd4a3600f7c71ca6968feb85e776 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 7 Jan 2023 02:59:32 +0300 Subject: [PATCH 042/376] Fix request --- osu.Game/Online/API/Requests/CommentPostRequest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/CommentPostRequest.cs b/osu.Game/Online/API/Requests/CommentPostRequest.cs index bd69c04bed..7012d479bd 100644 --- a/osu.Game/Online/API/Requests/CommentPostRequest.cs +++ b/osu.Game/Online/API/Requests/CommentPostRequest.cs @@ -27,7 +27,7 @@ namespace osu.Game.Online.API.Requests var req = base.CreateWebRequest(); req.Method = HttpMethod.Post; - req.AddParameter(@"comment[commentable_type]", Commentable.ToString()); + req.AddParameter(@"comment[commentable_type]", Commentable.ToString().ToLowerInvariant()); req.AddParameter(@"comment[commentable_id]", $"{CommentableId}"); req.AddParameter(@"comment[message]", Message); if (ReplyTo.HasValue) From 927773d56584c1b288642a3b143ef118d6ce4d65 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 7 Jan 2023 04:15:43 +0300 Subject: [PATCH 043/376] Display submitted comments locally --- .../Overlays/Comments/CommentsContainer.cs | 46 ++++++++++++++++++- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index c8a2ab39ae..98c186b273 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -3,6 +3,7 @@ #nullable disable +using System; using osu.Framework.Allocation; using osu.Framework.Graphics.Containers; using osu.Game.Online.API; @@ -115,7 +116,10 @@ namespace osu.Game.Overlays.Comments Padding = new MarginPadding { Left = 60 }, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Child = new NewCommentEditor() + Child = new NewCommentEditor + { + OnPost = prependPostedComments + } } } }, @@ -279,7 +283,6 @@ namespace osu.Game.Overlays.Comments { pinnedContent.AddRange(loaded.Where(d => d.Comment.Pinned)); content.AddRange(loaded.Where(d => !d.Comment.Pinned)); - deletedCommentsCounter.Count.Value += topLevelComments.Select(d => d.Comment).Count(c => c.IsDeleted && c.IsTopLevel); if (bundle.HasMore) @@ -322,6 +325,42 @@ namespace osu.Game.Overlays.Comments } } + private void prependPostedComments(CommentBundle bundle) + { + var topLevelComments = new List(); + + foreach (var comment in bundle.Comments) + { + // Exclude possible duplicated comments. + if (CommentDictionary.ContainsKey(comment.Id)) + continue; + + topLevelComments.Add(getDrawableComment(comment)); + } + + if (topLevelComments.Any()) + { + LoadComponentsAsync(topLevelComments, loaded => + { + if (content[0] is NoCommentsPlaceholder placeholder) + content.Remove(placeholder, true); + + foreach (var comment in loaded) + { + int pos = -1; + + if (content.Count > 0) + { + var first = content.FlowingChildren.First(); + pos = (int)(content.GetLayoutPosition(first) - 1); + } + + content.Insert(pos, comment); + } + }, (loadCancellation = new CancellationTokenSource()).Token); + } + } + private DrawableComment getDrawableComment(Comment comment) { if (CommentDictionary.TryGetValue(comment.Id, out var existing)) @@ -386,6 +425,8 @@ namespace osu.Game.Overlays.Comments [Resolved] private IAPIProvider api { get; set; } + public Action OnPost; + protected override void OnCommit(string text) { CommitButton.IsLoadingSpinnerShown = true; @@ -398,6 +439,7 @@ namespace osu.Game.Overlays.Comments { CommitButton.IsLoadingSpinnerShown = false; Current.Value = string.Empty; + OnPost?.Invoke(cb); }); api.Queue(req); } From 49ce50878d2c761fcc0a43132cf1669f9966d687 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 7 Jan 2023 04:15:53 +0300 Subject: [PATCH 044/376] Add simple test --- .../Online/TestSceneCommentsContainer.cs | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index 291ccd634d..86a574cf77 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -11,7 +11,11 @@ using osu.Game.Overlays; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Testing; +using osu.Framework.Utils; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; @@ -126,6 +130,24 @@ namespace osu.Game.Tests.Visual.Online commentsContainer.ChildrenOfType().Count(d => d.Comment.Pinned == withPinned) == 1); } + [TestCase] + public void TestPost() + { + setUpCommentsResponse(getExampleComments()); + AddStep("show comments", () => commentsContainer.ShowComments(CommentableType.Beatmapset, 123)); + setUpPostResponse(); + AddStep("Enter text", () => this.ChildrenOfType().Single().ChildrenOfType().Single().Current.Value = "comm"); + AddStep("Submit", () => this.ChildrenOfType().Single().ChildrenOfType().First().TriggerClick()); + AddUntilStep("Comment sent", () => + { + var text = this.ChildrenOfType().Single().ChildrenOfType().Single().Current.Value; + return this.ChildrenOfType().Any(x => + { + return x.ChildrenOfType().Any(y => y.Text == text); + }); + }); + } + private void setUpCommentsResponse(CommentBundle commentBundle) => AddStep("set up response", () => { @@ -139,6 +161,32 @@ namespace osu.Game.Tests.Visual.Online }; }); + private void setUpPostResponse() + => AddStep("set up response", () => + { + dummyAPI.HandleRequest = request => + { + if (!(request is CommentPostRequest req)) + return false; + + req.TriggerSuccess(new CommentBundle + { + Comments = new List + { + new Comment + { + Id = 98, + Message = req.Message, + LegacyName = "FirstUser", + CreatedAt = DateTimeOffset.Now, + VotesCount = 98, + } + } + }); + return true; + }; + }); + private CommentBundle getExampleComments(bool withPinned = false) { var bundle = new CommentBundle From 4baa2670953b4c201f5d70b64149fd6cb064d86d Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 7 Jan 2023 04:26:52 +0300 Subject: [PATCH 045/376] warnings --- osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index 86a574cf77..e58423241b 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -14,7 +14,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Framework.Testing; -using osu.Framework.Utils; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Online.API; using osu.Game.Online.API.Requests; @@ -140,7 +139,7 @@ namespace osu.Game.Tests.Visual.Online AddStep("Submit", () => this.ChildrenOfType().Single().ChildrenOfType().First().TriggerClick()); AddUntilStep("Comment sent", () => { - var text = this.ChildrenOfType().Single().ChildrenOfType().Single().Current.Value; + string text = this.ChildrenOfType().Single().ChildrenOfType().Single().Current.Value; return this.ChildrenOfType().Any(x => { return x.ChildrenOfType().Any(y => y.Text == text); @@ -187,7 +186,7 @@ namespace osu.Game.Tests.Visual.Online }; }); - private CommentBundle getExampleComments(bool withPinned = false) + private static CommentBundle getExampleComments(bool withPinned = false) { var bundle = new CommentBundle { From c2dd822e4a141f787d65200697ba1ea118493909 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 8 Jan 2023 14:08:36 -0800 Subject: [PATCH 046/376] Make pause overlay close with pause gameplay action --- osu.Game/Screens/Play/GameplayMenuOverlay.cs | 2 +- osu.Game/Screens/Play/PauseOverlay.cs | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/GameplayMenuOverlay.cs b/osu.Game/Screens/Play/GameplayMenuOverlay.cs index c681ef8f96..13f32d3b6a 100644 --- a/osu.Game/Screens/Play/GameplayMenuOverlay.cs +++ b/osu.Game/Screens/Play/GameplayMenuOverlay.cs @@ -189,7 +189,7 @@ namespace osu.Game.Screens.Play InternalButtons.Add(button); } - public bool OnPressed(KeyBindingPressEvent e) + public virtual bool OnPressed(KeyBindingPressEvent e) { switch (e.Action) { diff --git a/osu.Game/Screens/Play/PauseOverlay.cs b/osu.Game/Screens/Play/PauseOverlay.cs index 28044653e6..db2b87dae6 100644 --- a/osu.Game/Screens/Play/PauseOverlay.cs +++ b/osu.Game/Screens/Play/PauseOverlay.cs @@ -8,8 +8,10 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Graphics; +using osu.Framework.Input.Events; using osu.Game.Audio; using osu.Game.Graphics; +using osu.Game.Input.Bindings; using osu.Game.Skinning; using osuTK.Graphics; @@ -56,5 +58,17 @@ namespace osu.Game.Screens.Play pauseLoop.VolumeTo(0, TRANSITION_DURATION, Easing.OutQuad).Finally(_ => pauseLoop.Stop()); } + + public override bool OnPressed(KeyBindingPressEvent e) + { + switch (e.Action) + { + case GlobalAction.PauseGameplay: + BackAction.Invoke(); + return true; + } + + return base.OnPressed(e); + } } } From efded323e4818172add38612a149c8e8e91c4382 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 9 Jan 2023 16:49:36 +0900 Subject: [PATCH 047/376] Rename variables and avoid the need for a property --- .../Mods/TestSceneManiaModHidden.cs | 2 +- osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs | 5 +++++ osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs | 4 +--- osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs | 5 +++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHidden.cs b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHidden.cs index 44d206d9e1..204f26f151 100644 --- a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHidden.cs +++ b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHidden.cs @@ -14,6 +14,6 @@ namespace osu.Game.Rulesets.Mania.Tests.Mods [TestCase(0.5f)] [TestCase(0.2f)] [TestCase(0.8f)] - public void TestCoverage(float coverage) => CreateModTest(new ModTestData { Mod = new ManiaModHidden { CoverageAmount = { Value = coverage } }, PassCondition = () => true }); + public void TestCoverage(float coverage) => CreateModTest(new ModTestData { Mod = new ManiaModHidden { Coverage = { Value = coverage } }, PassCondition = () => true }); } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs index c6e9c339f4..800973ede5 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using osu.Framework.Bindables; using osu.Framework.Localisation; using osu.Game.Rulesets.Mania.UI; @@ -18,5 +19,9 @@ namespace osu.Game.Rulesets.Mania.Mods public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ManiaModHidden)).ToArray(); protected override CoverExpandDirection ExpandDirection => CoverExpandDirection.AlongScroll; + + // This could be customisable like ManiaModHidden in the future if there's any demand. + // At that point, the bindable could be moved to `ManiaModPlayfieldCover`. + public override BindableNumber Coverage { get; } = new BindableFloat(0.5f); } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs index 2eb9e6d1eb..50d40249c1 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Mania.Mods public override double ScoreMultiplier => 1; [SettingSource("Coverage", "The proportion of playfield height that notes will be hidden for.")] - public BindableNumber CoverageAmount { get; } = new BindableFloat(0.5f) + public override BindableNumber Coverage { get; } = new BindableFloat(0.5f) { Precision = 0.1f, MinValue = 0.2f, @@ -24,8 +24,6 @@ namespace osu.Game.Rulesets.Mania.Mods Default = 0.5f, }; - protected override float Coverage => CoverageAmount.Value; - public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ManiaModFadeIn)).ToArray(); protected override CoverExpandDirection ExpandDirection => CoverExpandDirection.AgainstScroll; diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs index bfb70938b9..45d0184d1d 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Mania.Objects; @@ -22,7 +23,7 @@ namespace osu.Game.Rulesets.Mania.Mods /// protected abstract CoverExpandDirection ExpandDirection { get; } - protected virtual float Coverage => 0.5f; + public abstract BindableNumber Coverage { get; } public virtual void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { @@ -38,7 +39,7 @@ namespace osu.Game.Rulesets.Mania.Mods { c.RelativeSizeAxes = Axes.Both; c.Direction = ExpandDirection; - c.Coverage = Coverage; + c.Coverage = Coverage.Value; })); } } From 0f1fe1d6832d0c6dd2f29e30a5d142b2fbfc023e Mon Sep 17 00:00:00 2001 From: tsrk Date: Mon, 9 Jan 2023 21:48:53 +0100 Subject: [PATCH 048/376] refactor(hud/gameplay/SongProgress): Add interface to designate `SongProgressBar`s --- .../Visual/Gameplay/TestSceneHUDOverlay.cs | 16 +++++++++++++--- .../Multiplayer/TestSceneMultiSpectatorScreen.cs | 2 +- osu.Game/Screens/Play/HUD/DefaultSongProgress.cs | 2 +- osu.Game/Screens/Play/HUD/ISongProgressBar.cs | 16 ++++++++++++++++ osu.Game/Screens/Play/HUD/SongProgressBar.cs | 10 ++++------ 5 files changed, 35 insertions(+), 11 deletions(-) create mode 100644 osu.Game/Screens/Play/HUD/ISongProgressBar.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs index 29fadd151f..713183ebaf 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs @@ -188,7 +188,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestInputDoesntWorkWhenHUDHidden() { - SongProgressBar? getSongProgress() => hudOverlay.ChildrenOfType().SingleOrDefault(); + ISongProgressBar? getSongProgress() => hudOverlay.ChildrenOfType().SingleOrDefault(); bool seeked = false; @@ -204,7 +204,7 @@ namespace osu.Game.Tests.Visual.Gameplay Debug.Assert(progress != null); - progress.ShowHandle = true; + progress.Interactive = true; progress.OnSeek += _ => seeked = true; }); @@ -213,7 +213,17 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("attempt seek", () => { - InputManager.MoveMouseTo(getSongProgress()); + switch (getSongProgress()) + { + case SongProgressBar defaultBar: + InputManager.MoveMouseTo(defaultBar); + break; + + case ArgonSongProgressBar argonBar: + InputManager.MoveMouseTo(argonBar); + break; + } + InputManager.Click(MouseButton.Left); }); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index c2036984c1..dd891b456c 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -121,7 +121,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("all interactive elements removed", () => this.ChildrenOfType().All(p => !p.ChildrenOfType().Any() && !p.ChildrenOfType().Any() && - p.ChildrenOfType().SingleOrDefault()?.ShowHandle == false)); + p.ChildrenOfType().SingleOrDefault()?.Interactive == false)); AddStep("restore config hud visibility", () => config.SetValue(OsuSetting.HUDVisibilityMode, originalConfigValue)); } diff --git a/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs b/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs index 53866312a0..cb629a0b77 100644 --- a/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs +++ b/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs @@ -133,7 +133,7 @@ namespace osu.Game.Screens.Play.HUD private void updateBarVisibility() { - bar.ShowHandle = AllowSeeking.Value; + bar.Interactive = AllowSeeking.Value; updateInfoMargin(); } diff --git a/osu.Game/Screens/Play/HUD/ISongProgressBar.cs b/osu.Game/Screens/Play/HUD/ISongProgressBar.cs new file mode 100644 index 0000000000..f1a219e18b --- /dev/null +++ b/osu.Game/Screens/Play/HUD/ISongProgressBar.cs @@ -0,0 +1,16 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; + +namespace osu.Game.Screens.Play.HUD +{ + public interface ISongProgressBar + { + public Action? OnSeek { get; set; } + public double StartTime { set; } + public double EndTime { set; } + public double CurrentTime { set; } + public bool Interactive { get; set; } + } +} diff --git a/osu.Game/Screens/Play/HUD/SongProgressBar.cs b/osu.Game/Screens/Play/HUD/SongProgressBar.cs index 28059d4911..fade562e3c 100644 --- a/osu.Game/Screens/Play/HUD/SongProgressBar.cs +++ b/osu.Game/Screens/Play/HUD/SongProgressBar.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 osuTK; using osuTK.Graphics; @@ -15,9 +13,9 @@ using osu.Framework.Threading; namespace osu.Game.Screens.Play.HUD { - public partial class SongProgressBar : SliderBar + public partial class SongProgressBar : SliderBar, ISongProgressBar { - public Action OnSeek; + public Action? OnSeek { get; set; } private readonly Box fill; private readonly Container handleBase; @@ -25,7 +23,7 @@ namespace osu.Game.Screens.Play.HUD private bool showHandle; - public bool ShowHandle + public bool Interactive { get => showHandle; set @@ -142,7 +140,7 @@ namespace osu.Game.Screens.Play.HUD handleBase.X = newX; } - private ScheduledDelegate scheduledSeek; + private ScheduledDelegate? scheduledSeek; protected override void OnUserChange(double value) { From f6265197e84a44fe76df79a53feb3a54976cd6c2 Mon Sep 17 00:00:00 2001 From: tsrk Date: Mon, 9 Jan 2023 21:55:10 +0100 Subject: [PATCH 049/376] feat(hud/gameplay): Add Argon variant of `SongProgressBar` --- .../Screens/Play/HUD/ArgonSongProgressBar.cs | 249 ++++++++++++++++++ 1 file changed, 249 insertions(+) create mode 100644 osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs diff --git a/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs b/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs new file mode 100644 index 0000000000..3ac7223f1d --- /dev/null +++ b/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs @@ -0,0 +1,249 @@ +// 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.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Events; +using osu.Framework.Threading; +using osu.Framework.Utils; +using osu.Game.Graphics; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.Play.HUD +{ + public partial class ArgonSongProgressBar : SliderBar, ISongProgressBar + { + private readonly float baseHeight; + private readonly float catchupBaseDepth; + + private readonly RoundedBar playfieldBar; + private readonly RoundedBar catchupBar; + + private readonly Box background; + + private readonly BindableBool showBackground = new BindableBool(); + + public bool ShowBackground + { + get => showBackground.Value; + set => showBackground.Value = value; + } + + private const float alpha_threshold = 2500; + + public Action? OnSeek { get; set; } + + public double StartTime + { + private get => CurrentNumber.MinValue; + set => CurrentNumber.MinValue = value; + } + + public double EndTime + { + private get => CurrentNumber.MaxValue; + set => CurrentNumber.MaxValue = value; + } + + public double CurrentTime + { + private get => CurrentNumber.Value; + set => CurrentNumber.Value = value; + } + + public double ReferenceTime + { + private get => currentReference.Value; + set => currentReference.Value = value; + } + + private double length => EndTime - StartTime; + + private readonly BindableNumber currentReference; + + public bool Interactive { get; set; } + + public ArgonSongProgressBar(float barHeight) + { + currentReference = new BindableDouble(); + setupAlternateValue(); + + StartTime = 0; + EndTime = 1; + + RelativeSizeAxes = Axes.X; + baseHeight = barHeight; + Height = baseHeight; + + CornerRadius = 5; + Masking = true; + + Children = new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + }, + catchupBar = new RoundedBar + { + Name = "Audio bar", + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + CornerRadius = 5, + AlwaysPresent = true, + RelativeSizeAxes = Axes.Both + }, + playfieldBar = new RoundedBar + { + Name = "Playfield bar", + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + CornerRadius = 5, + AccentColour = Color4.White, + RelativeSizeAxes = Axes.Both + }, + }; + catchupBaseDepth = catchupBar.Depth; + } + + private void setupAlternateValue() + { + CurrentNumber.MaxValueChanged += v => currentReference.MaxValue = v; + CurrentNumber.MinValueChanged += v => currentReference.MinValue = v; + CurrentNumber.PrecisionChanged += v => currentReference.Precision = v; + } + + private float normalizedReference + { + get + { + if (EndTime - StartTime == 0) + return 1; + + return (float)((ReferenceTime - StartTime) / length); + } + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + catchupBar.AccentColour = colours.BlueLight; + showBackground.BindValueChanged(_ => updateBackground(), true); + } + + private void updateBackground() + { + background.FadeTo(showBackground.Value ? 1 : 0, 200, Easing.In); + } + + protected override bool OnHover(HoverEvent e) + { + if (Interactive) + this.ResizeHeightTo(baseHeight * 3.5f, 200, Easing.Out); + + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + if (Interactive) + this.ResizeHeightTo(baseHeight, 200, Easing.In); + + base.OnHoverLost(e); + } + + protected override void UpdateValue(float value) + { + // + } + + protected override void Update() + { + base.Update(); + + playfieldBar.Length = (float)Interpolation.Lerp(playfieldBar.Length, NormalizedValue, Math.Clamp(Time.Elapsed / 40, 0, 1)); + catchupBar.Length = (float)Interpolation.Lerp(catchupBar.Length, normalizedReference, Math.Clamp(Time.Elapsed / 40, 0, 1)); + + if (ReferenceTime < CurrentTime) + ChangeChildDepth(catchupBar, playfieldBar.Depth - 0.1f); + else + ChangeChildDepth(catchupBar, catchupBaseDepth); + + float timeDelta = (float)(Math.Abs(CurrentTime - ReferenceTime)); + catchupBar.Alpha = MathHelper.Clamp(timeDelta, 0, alpha_threshold) / alpha_threshold; + } + + private ScheduledDelegate? scheduledSeek; + + protected override void OnUserChange(double value) + { + scheduledSeek?.Cancel(); + scheduledSeek = Schedule(() => + { + if (Interactive) + OnSeek?.Invoke(value); + }); + } + + private partial class RoundedBar : Container + { + private readonly Box fill; + private readonly Container mask; + private float length; + + public RoundedBar() + { + Masking = true; + Children = new[] + { + mask = new Container + { + Masking = true, + RelativeSizeAxes = Axes.Y, + Size = new Vector2(1), + Child = fill = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Colour4.White + } + } + }; + } + + public float Length + { + get => length; + set + { + length = value; + mask.Width = value * DrawWidth; + fill.Width = value * DrawWidth; + } + } + + public new float CornerRadius + { + get => base.CornerRadius; + set + { + base.CornerRadius = value; + mask.CornerRadius = value; + } + } + + public ColourInfo AccentColour + { + get => fill.Colour; + set => fill.Colour = value; + } + } + } +} From 28d2d766ebdb595b138761f4da03149e0894e7af Mon Sep 17 00:00:00 2001 From: tsrk Date: Mon, 9 Jan 2023 21:57:32 +0100 Subject: [PATCH 050/376] refactor(hud/gameplay/SongProgressInfo): minor changes to text positioning, font and colour --- osu.Game/Screens/Play/HUD/SongProgressInfo.cs | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs index fb5f5cc916..8a5c24a1f1 100644 --- a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs +++ b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs @@ -10,6 +10,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using System; +using osu.Framework.Graphics.Sprites; namespace osu.Game.Screens.Play.HUD { @@ -27,13 +28,33 @@ namespace osu.Game.Screens.Play.HUD private double songLength => endTime - startTime; - private const int margin = 10; + public FontUsage Font + { + set + { + timeCurrent.Font = value; + timeLeft.Font = value; + progress.Font = value; + } + } + + public Colour4 TextColour + { + set + { + timeCurrent.Colour = value; + timeLeft.Colour = value; + progress.Colour = value; + } + } public double StartTime { set => startTime = value; } + public bool ShowProgress = true; + public double EndTime { set => endTime = value; @@ -76,6 +97,7 @@ namespace osu.Game.Screens.Play.HUD Origin = Anchor.Centre, Anchor = Anchor.Centre, AutoSizeAxes = Axes.Both, + Alpha = ShowProgress ? 1 : 0, Child = new UprightAspectMaintainingContainer { Origin = Anchor.Centre, @@ -99,15 +121,15 @@ namespace osu.Game.Screens.Play.HUD AutoSizeAxes = Axes.Both, Child = new UprightAspectMaintainingContainer { - Origin = Anchor.Centre, - Anchor = Anchor.Centre, + Origin = Anchor.CentreRight, + Anchor = Anchor.CentreRight, AutoSizeAxes = Axes.Both, Scaling = ScaleMode.Vertical, ScalingFactor = 0.5f, Child = timeLeft = new SizePreservingSpriteText { - Origin = Anchor.Centre, - Anchor = Anchor.Centre, + Origin = Anchor.CentreRight, + Anchor = Anchor.CentreRight, Colour = colours.BlueLighter, Font = OsuFont.Numeric, } @@ -128,7 +150,7 @@ namespace osu.Game.Screens.Play.HUD if (currentPercent != previousPercent) { - progress.Text = currentPercent.ToString() + @"%"; + progress.Text = currentPercent + @"%"; previousPercent = currentPercent; } From 5952cd08a22e16d96f20815f21d3b7b50dcec71a Mon Sep 17 00:00:00 2001 From: tsrk Date: Mon, 9 Jan 2023 21:58:53 +0100 Subject: [PATCH 051/376] feat(hud/gameplay): implement Argon song progress density graph (SegmentedGraph) --- .../Play/HUD/ArgonSongProgressGraph.cs | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 osu.Game/Screens/Play/HUD/ArgonSongProgressGraph.cs diff --git a/osu.Game/Screens/Play/HUD/ArgonSongProgressGraph.cs b/osu.Game/Screens/Play/HUD/ArgonSongProgressGraph.cs new file mode 100644 index 0000000000..2c82faf7b2 --- /dev/null +++ b/osu.Game/Screens/Play/HUD/ArgonSongProgressGraph.cs @@ -0,0 +1,62 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using osu.Framework.Graphics; +using osu.Game.Rulesets.Objects; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Screens.Play.HUD +{ + public partial class ArgonSongProgressGraph : SegmentedGraph + { + private IEnumerable? objects; + + public IEnumerable Objects + { + set + { + objects = value; + + const int granularity = 300; + int[] values = new int[granularity]; + + if (!objects.Any()) + return; + + double firstHit = objects.First().StartTime; + double lastHit = objects.Max(o => o.GetEndTime()); + + if (lastHit == 0) + lastHit = objects.Last().StartTime; + + double interval = (lastHit - firstHit + 1) / granularity; + + foreach (var h in objects) + { + double endTime = h.GetEndTime(); + + Debug.Assert(endTime >= h.StartTime); + + int startRange = (int)((h.StartTime - firstHit) / interval); + int endRange = (int)((endTime - firstHit) / interval); + for (int i = startRange; i <= endRange; i++) + values[i]++; + } + + Values = values; + } + } + + public ArgonSongProgressGraph() + : base(5) + { + for (int i = 0; i < 5; i++) + { + TierColours[i] = Colour4.White.Opacity(1 / 5f * 0.85f); + } + } + } +} From 91cde5ffbff37689c318d7f49aef1f1819843f62 Mon Sep 17 00:00:00 2001 From: tsrk Date: Mon, 9 Jan 2023 21:59:48 +0100 Subject: [PATCH 052/376] feat(hud/gameplay): implement Argon variant of `SongProgress` --- .../Screens/Play/HUD/ArgonSongProgress.cs | 139 ++++++++++++++++++ osu.Game/Skinning/ArgonSkin.cs | 9 +- 2 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Screens/Play/HUD/ArgonSongProgress.cs diff --git a/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs b/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs new file mode 100644 index 0000000000..c36f881ec2 --- /dev/null +++ b/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs @@ -0,0 +1,139 @@ +// 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.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Timing; +using osu.Game.Configuration; +using osu.Game.Graphics; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.UI; + +namespace osu.Game.Screens.Play.HUD +{ + public partial class ArgonSongProgress : SongProgress + { + private readonly SongProgressInfo info; + private readonly ArgonSongProgressGraph graph; + private readonly ArgonSongProgressBar bar; + + private const float bar_height = 10; + + public readonly Bindable AllowSeeking = new BindableBool(); + + [SettingSource("Show difficulty graph", "Whether a graph displaying difficulty throughout the beatmap should be shown")] + public Bindable ShowGraph { get; } = new BindableBool(true); + + [Resolved] + private DrawableRuleset? drawableRuleset { get; set; } + + private IClock referenceClock => drawableRuleset?.FrameStableClock ?? GameplayClock; + + [Resolved] + private Player? player { get; set; } + + public ArgonSongProgress() + { + Anchor = Anchor.BottomCentre; + Origin = Anchor.BottomCentre; + Children = new Drawable[] + { + info = new SongProgressInfo + { + Origin = Anchor.TopLeft, + Name = "Info", + Anchor = Anchor.TopLeft, + RelativeSizeAxes = Axes.X, + ShowProgress = false + }, + graph = new ArgonSongProgressGraph + { + Name = "Difficulty graph", + Origin = Anchor.BottomLeft, + Anchor = Anchor.BottomLeft, + RelativeSizeAxes = Axes.X, + Masking = true, + CornerRadius = 5, + }, + bar = new ArgonSongProgressBar(bar_height) + { + Name = "Seek bar", + Origin = Anchor.BottomLeft, + Anchor = Anchor.BottomLeft, + OnSeek = time => player?.Seek(time), + } + }; + RelativeSizeAxes = Axes.X; + } + + [BackgroundDependencyLoader] + private void load() + { + base.LoadComplete(); + + if (drawableRuleset != null) + { + if (player?.Configuration.AllowUserInteraction == true) + ((IBindable)AllowSeeking).BindTo(drawableRuleset.HasReplayLoaded); + } + + info.ShowProgress = false; + info.TextColour = Colour4.White; + info.Font = OsuFont.Torus.With(size: 18, weight: FontWeight.Bold); + } + + protected override void LoadComplete() + { + AllowSeeking.BindValueChanged(_ => updateBarVisibility(), true); + ShowGraph.BindValueChanged(_ => updateGraphVisibility(), true); + } + + protected override void UpdateObjects(IEnumerable objects) + { + graph.Objects = objects; + + info.StartTime = bar.StartTime = FirstHitTime; + info.EndTime = bar.EndTime = LastHitTime; + } + + private void updateBarVisibility() + { + bar.Interactive = AllowSeeking.Value; + } + + private void updateGraphVisibility() + { + graph.FadeTo(ShowGraph.Value ? 1 : 0, 200, Easing.In); + bar.ShowBackground = !ShowGraph.Value; + } + + protected override void Update() + { + base.Update(); + Height = bar.Height + bar_height + info.Height; + graph.Height = bar.Height; + } + + protected override void PopIn() + { + this.FadeIn(500, Easing.OutQuint); + } + + protected override void PopOut() + { + this.FadeOut(100); + } + + protected override void UpdateProgress(double progress, bool isIntro) + { + bar.ReferenceTime = GameplayClock.CurrentTime; + + if (isIntro) + bar.CurrentTime = 0; + else + bar.CurrentTime = referenceClock.CurrentTime; + } + } +} diff --git a/osu.Game/Skinning/ArgonSkin.cs b/osu.Game/Skinning/ArgonSkin.cs index d78147aaea..53c6c1e5ce 100644 --- a/osu.Game/Skinning/ArgonSkin.cs +++ b/osu.Game/Skinning/ArgonSkin.cs @@ -108,6 +108,7 @@ namespace osu.Game.Skinning var accuracy = container.OfType().FirstOrDefault(); var combo = container.OfType().FirstOrDefault(); var ppCounter = container.OfType().FirstOrDefault(); + var songProgress = container.OfType().FirstOrDefault(); if (score != null) { @@ -158,6 +159,12 @@ namespace osu.Game.Skinning // origin flipped to match scale above. hitError2.Origin = Anchor.CentreLeft; } + + if (songProgress != null) + { + songProgress.Position = new Vector2(0, -10); + songProgress.Scale = new Vector2(0.9f, 1); + } } }) { @@ -167,7 +174,7 @@ namespace osu.Game.Skinning new DefaultScoreCounter(), new DefaultAccuracyCounter(), new DefaultHealthDisplay(), - new DefaultSongProgress(), + new ArgonSongProgress(), new BarHitErrorMeter(), new BarHitErrorMeter(), new PerformancePointsCounter() From 48deef4056a3b0a25f6dda5e440aacaac69dfa23 Mon Sep 17 00:00:00 2001 From: tsrk Date: Mon, 9 Jan 2023 22:07:18 +0100 Subject: [PATCH 053/376] test: adapt and create tests to cover new components --- .../Archives/modified-argon-20221024.osk | Bin 0 -> 1412 bytes .../Skins/SkinDeserialisationTest.cs | 2 + .../SkinnableHUDComponentTestScene.cs | 5 +- .../TestSceneArgonSongProgressGraph.cs | 73 ++++++++++++++++++ .../Visual/Gameplay/TestSceneSongProgress.cs | 2 + 5 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Tests/Resources/Archives/modified-argon-20221024.osk create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneArgonSongProgressGraph.cs diff --git a/osu.Game.Tests/Resources/Archives/modified-argon-20221024.osk b/osu.Game.Tests/Resources/Archives/modified-argon-20221024.osk new file mode 100644 index 0000000000000000000000000000000000000000..28b6a001ebd37b63c3e6c1b64d2cab3af0b9e0a5 GIT binary patch literal 1412 zcmWIWW@Zs#U|`^2*fJ?1H1DEC$y^|BJ6ME)p*TA;PcJhsQ?yU#0!|wxs6MaP; zdzJ`Zio6+_sVX-6j+*73+fz@=Ddunf;8}N&Wp|_Gv)})wsK&52`R$p0vXFo61|e-9 z3nsOx4X>iU)Uj=urek7!Vuo2la7?jyoKPt{Z(p}a+qudl9+sz8TSXKnEOI@%_vE|u zq^=k8YP)rO|HeO+sD3EZ^(r7VTB9lAy5%Nrx$SD!swbU0f>2l803Y_ytI71tm6E<)z6*=1q6KZKI0p@DJbBSzFufZN1&IE*ZK3^fk77x zj0}t}gX&+xkqqC+{OAbWM=?)V1{?zTT%jxr`&!0|zULZ8D@~CQOrRvO1 z)tNsl=T&C@3~2s(r*YZ~*7WpePg9>QeQnwFhT&t0NWvtqJuzDuP#tJ`-1GGgMh1r0 zK-Y-@9q5~wndcGe;+&sbke`>DS5gdi>Dy_6*|!Y@j^F40%cpjJ+k{s~HnLTon3UUS zm^Q6Ue<}Z}s=^~8E9a!Fko^5_a`^Goucy7dWVR(5{8<0_e@oq*ck9ldU-Y8-bJwDa zskQuz%`cwV)m0;4t&rWxaBQMe_pCMRrloL72WIZyuseG9hN&ML3b*k0FJ9l^7iqls z$#r4(Zh;uZGdv-3t$m9Z?Yin!*YfL99ka3V)N6}(_{K*pulZq{v+!=9fcznGY2!l{ z&nxeoES+$fb7B9X{=G-VU%O^se3E~4tBBOEb+Hbwk5`oyD{mK@z4T?=ubx#Qz4rID z!};!1e`P3-{oR!P-m$=z$^Vi9N7$+T&Rc$P9`b#1BD!(EW_`Ks20OlQ^2b*{@`yX6 zEIVJSpQ#|ZP`#(+kk;e74U2=#6c;vsKKUbl{`|f>hLaw+N8{Hunu%t)%{2P{(%LSS{*LbeYD9784v0|*ks+ClG?0RBJpBb64Sq#;wnp5tDK#7{Tb)|74oU2A-DK1 zRJg34b=@ZA;%~vd(gyx}nh%@&JKNH@k~8A<{>w2_H(t2ue>u)4%z6i>UVn^?Nz3iK zb{js|Z2Qj|;LXS+!hpN<0R|WZG=eBtS%j_&J;OuwFfcS8hU$W6e{`+rSrMT%1sGx2 gGbXwj=uwO?BY+tr!UMcn*+2?dfbbKLu3-W3058Krn*aa+ literal 0 HcmV?d00001 diff --git a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs index ff665499ae..2e8eb48f0b 100644 --- a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs +++ b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs @@ -41,6 +41,8 @@ namespace osu.Game.Tests.Skins "Archives/modified-default-20220818.osk", // Covers longest combo counter "Archives/modified-default-20221012.osk", + // Covers Argon variant of song progress bar + "Archives/modified-argon-20221024.osk", // Covers TextElement and BeatmapInfoDrawable "Archives/modified-default-20221102.osk" }; diff --git a/osu.Game.Tests/Visual/Gameplay/SkinnableHUDComponentTestScene.cs b/osu.Game.Tests/Visual/Gameplay/SkinnableHUDComponentTestScene.cs index 545b3c2cf4..f54f50795e 100644 --- a/osu.Game.Tests/Visual/Gameplay/SkinnableHUDComponentTestScene.cs +++ b/osu.Game.Tests/Visual/Gameplay/SkinnableHUDComponentTestScene.cs @@ -20,7 +20,9 @@ namespace osu.Game.Tests.Visual.Gameplay { var implementation = skin is LegacySkin ? CreateLegacyImplementation() - : CreateDefaultImplementation(); + : skin is ArgonSkin + ? CreateArgonImplementation() + : CreateDefaultImplementation(); implementation.Anchor = Anchor.Centre; implementation.Origin = Anchor.Centre; @@ -29,6 +31,7 @@ namespace osu.Game.Tests.Visual.Gameplay }); protected abstract Drawable CreateDefaultImplementation(); + protected virtual Drawable CreateArgonImplementation() => CreateDefaultImplementation(); protected abstract Drawable CreateLegacyImplementation(); } } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneArgonSongProgressGraph.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneArgonSongProgressGraph.cs new file mode 100644 index 0000000000..159ee849e1 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneArgonSongProgressGraph.cs @@ -0,0 +1,73 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Diagnostics; +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Framework.Testing; +using osu.Framework.Utils; +using osu.Game.Rulesets.Objects; +using osu.Game.Screens.Play.HUD; + +namespace osu.Game.Tests.Visual.Gameplay +{ + [TestFixture] + public partial class TestSceneArgonSongProgressGraph : OsuTestScene + { + private TestArgonSongProgressGraph? graph; + + [SetUpSteps] + public void SetupSteps() + { + AddStep("add new big graph", () => + { + if (graph != null) + { + graph.Expire(); + graph = null; + } + + Add(graph = new TestArgonSongProgressGraph + { + RelativeSizeAxes = Axes.X, + Height = 200, + Anchor = Anchor.TopLeft, + Origin = Anchor.TopLeft, + }); + }); + } + + [Test] + public void TestGraphRecreation() + { + AddAssert("ensure not created", () => graph!.CreationCount == 0); + AddStep("display values", displayRandomValues); + AddUntilStep("wait for creation count", () => graph!.CreationCount == 1); + AddRepeatStep("new values", displayRandomValues, 5); + AddWaitStep("wait some", 5); + AddAssert("ensure recreation debounced", () => graph!.CreationCount == 2); + } + + private void displayRandomValues() + { + Debug.Assert(graph != null); + var objects = new List(); + for (double i = 0; i < 5000; i += RNG.NextDouble() * 10 + i / 1000) + objects.Add(new HitObject { StartTime = i }); + + graph.Objects = objects; + } + + private partial class TestArgonSongProgressGraph : ArgonSongProgressGraph + { + public int CreationCount { get; private set; } + + protected override void RecreateGraph() + { + base.RecreateGraph(); + CreationCount++; + } + } + } +} diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs index 2e579cc522..415a3c5b07 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs @@ -72,6 +72,8 @@ namespace osu.Game.Tests.Visual.Gameplay protected override Drawable CreateDefaultImplementation() => new DefaultSongProgress(); + protected override Drawable CreateArgonImplementation() => new ArgonSongProgress(); + protected override Drawable CreateLegacyImplementation() => new LegacySongProgress(); } } From eac8e9f6fb2756b4a5529dec30065dc8706ed3c1 Mon Sep 17 00:00:00 2001 From: tsrk Date: Mon, 9 Jan 2023 22:21:34 +0100 Subject: [PATCH 054/376] test: make test not actually test anything --- .../Visual/Gameplay/TestSceneArgonSongProgressGraph.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneArgonSongProgressGraph.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneArgonSongProgressGraph.cs index 159ee849e1..e7feadc72b 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneArgonSongProgressGraph.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneArgonSongProgressGraph.cs @@ -39,14 +39,10 @@ namespace osu.Game.Tests.Visual.Gameplay } [Test] - public void TestGraphRecreation() + public void Test() { AddAssert("ensure not created", () => graph!.CreationCount == 0); AddStep("display values", displayRandomValues); - AddUntilStep("wait for creation count", () => graph!.CreationCount == 1); - AddRepeatStep("new values", displayRandomValues, 5); - AddWaitStep("wait some", 5); - AddAssert("ensure recreation debounced", () => graph!.CreationCount == 2); } private void displayRandomValues() From 38bb7ac0c7901cbca12a4f787fe2d28eaa0591a8 Mon Sep 17 00:00:00 2001 From: Wleter Date: Tue, 10 Jan 2023 21:16:34 +0100 Subject: [PATCH 055/376] 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 056/376] 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 057/376] 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 776b60f3b3b133ecd41bc284e727e333c670f949 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 10 Jan 2023 14:05:08 -0800 Subject: [PATCH 058/376] Fix manual input manager test scenes not matching game input hierarchy Fix popover using on key down Fix popover not expiring when using global action --- osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs | 12 +++++++++++- .../Tests/Visual/OsuManualInputManagerTestScene.cs | 10 ++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs b/osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs index e66e48373c..d89322cecd 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs @@ -5,6 +5,7 @@ using JetBrains.Annotations; using osu.Framework.Allocation; +using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; @@ -14,6 +15,7 @@ using osu.Framework.Input.Events; using osu.Game.Input.Bindings; using osu.Game.Overlays; using osuTK; +using osuTK.Input; namespace osu.Game.Graphics.UserInterfaceV2 { @@ -58,6 +60,14 @@ namespace osu.Game.Graphics.UserInterfaceV2 this.FadeOut(fade_duration, Easing.OutQuint); } + protected override bool OnKeyDown(KeyDownEvent e) + { + if (e.Key == Key.Escape) + return false; // disable the framework-level handling of escape key for conformity (we use GlobalAction.Back). + + return base.OnKeyDown(e); + } + public bool OnPressed(KeyBindingPressEvent e) { if (e.Repeat) @@ -68,7 +78,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 if (e.Action == GlobalAction.Back) { - Hide(); + this.HidePopover(); return true; } diff --git a/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs b/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs index b0043b902c..8e0ee896a5 100644 --- a/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs +++ b/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs @@ -46,21 +46,23 @@ namespace osu.Game.Tests.Visual { var mainContent = content = new Container { RelativeSizeAxes = Axes.Both }; + var inputContainer = new Container { RelativeSizeAxes = Axes.Both }; + if (DisplayCursorForManualInput) { var cursorDisplay = new GlobalCursorDisplay { RelativeSizeAxes = Axes.Both }; - cursorDisplay.Add(new OsuTooltipContainer(cursorDisplay.MenuCursor) + cursorDisplay.Add(content = new OsuTooltipContainer(cursorDisplay.MenuCursor) { RelativeSizeAxes = Axes.Both, - Child = mainContent }); - mainContent = cursorDisplay; + inputContainer.Add(cursorDisplay); + mainContent = inputContainer; } if (CreateNestedActionContainer) - mainContent = new GlobalActionContainer(null).WithChild(mainContent); + inputContainer.Add(new GlobalActionContainer(null)); base.Content.AddRange(new Drawable[] { From 51dbe2c3a33fb6033e1af6730cb49b1ba50c9a55 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 10 Jan 2023 15:43:06 -0800 Subject: [PATCH 059/376] Refactor pause test to actually use back action keybinding --- .../Visual/Gameplay/TestScenePause.cs | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs index 7880a849a2..910a6f28cf 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs @@ -5,6 +5,7 @@ using System.Linq; using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -34,6 +35,12 @@ namespace osu.Game.Tests.Visual.Gameplay base.Content.Add(content = new GlobalCursorDisplay { RelativeSizeAxes = Axes.Both }); } + [BackgroundDependencyLoader] + private void load() + { + LocalConfig.SetValue(OsuSetting.UIHoldActivationDelay, 0.0); + } + [SetUpSteps] public override void SetUpSteps() { @@ -144,7 +151,7 @@ namespace osu.Game.Tests.Visual.Gameplay { AddStep("disable pause support", () => Player.Configuration.AllowPause = false); - pauseFromUserExitKey(); + pauseViaBackAction(); confirmExited(); } @@ -156,7 +163,7 @@ namespace osu.Game.Tests.Visual.Gameplay pauseAndConfirm(); resume(); - pauseFromUserExitKey(); + pauseViaBackAction(); confirmResumed(); confirmNotExited(); @@ -214,7 +221,7 @@ namespace osu.Game.Tests.Visual.Gameplay confirmClockRunning(false); - AddStep("exit via user pause", () => Player.ExitViaPause()); + pauseViaBackAction(); confirmExited(); } @@ -224,11 +231,11 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("wait for fail", () => Player.GameplayState.HasFailed); // will finish the fail animation and show the fail/pause screen. - AddStep("attempt exit via pause key", () => Player.ExitViaPause()); + pauseViaBackAction(); AddAssert("fail overlay shown", () => Player.FailOverlayVisible); // will actually exit. - AddStep("exit via pause key", () => Player.ExitViaPause()); + pauseViaBackAction(); confirmExited(); } @@ -327,7 +334,7 @@ namespace osu.Game.Tests.Visual.Gameplay private void pauseAndConfirm() { - pauseFromUserExitKey(); + pauseViaBackAction(); confirmPaused(); } @@ -374,7 +381,7 @@ namespace osu.Game.Tests.Visual.Gameplay } private void restart() => AddStep("restart", () => Player.Restart()); - private void pauseFromUserExitKey() => AddStep("user pause", () => Player.ExitViaPause()); + private void pauseViaBackAction() => AddStep("press escape", () => InputManager.Key(Key.Escape)); private void resume() => AddStep("resume", () => Player.Resume()); private void confirmPauseOverlayShown(bool isShown) => @@ -405,8 +412,6 @@ namespace osu.Game.Tests.Visual.Gameplay public bool PauseOverlayVisible => PauseOverlay.State.Value == Visibility.Visible; - public void ExitViaPause() => PerformExit(true); - public void ExitViaQuickExit() => PerformExit(false); public override void OnEntering(ScreenTransitionEvent e) From 404d34f5920d8caced05226cc9f234ce585d3b7e Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 10 Jan 2023 15:43:50 -0800 Subject: [PATCH 060/376] Refactor pause test to actually use quick exit action keybinding --- .../Visual/Gameplay/TestScenePause.cs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs index 910a6f28cf..ca221b6b1c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs @@ -177,7 +177,7 @@ namespace osu.Game.Tests.Visual.Gameplay pauseAndConfirm(); resume(); - AddStep("pause via exit key", () => Player.ExitViaQuickExit()); + exitViaQuickExitAction(); confirmResumed(); AddAssert("exited", () => !Player.IsCurrentScreen()); @@ -252,7 +252,7 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestQuickExitFromFailedGameplay() { AddUntilStep("wait for fail", () => Player.GameplayState.HasFailed); - AddStep("quick exit", () => Player.GameplayClockContainer.ChildrenOfType().First().Action?.Invoke()); + exitViaQuickExitAction(); confirmExited(); } @@ -268,7 +268,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestQuickExitFromGameplay() { - AddStep("quick exit", () => Player.GameplayClockContainer.ChildrenOfType().First().Action?.Invoke()); + exitViaQuickExitAction(); confirmExited(); } @@ -382,6 +382,15 @@ namespace osu.Game.Tests.Visual.Gameplay private void restart() => AddStep("restart", () => Player.Restart()); private void pauseViaBackAction() => AddStep("press escape", () => InputManager.Key(Key.Escape)); + + private void exitViaQuickExitAction() => AddStep("press ctrl-tilde", () => + { + InputManager.PressKey(Key.ControlLeft); + InputManager.PressKey(Key.Tilde); + InputManager.ReleaseKey(Key.Tilde); + InputManager.ReleaseKey(Key.ControlLeft); + }); + private void resume() => AddStep("resume", () => Player.Resume()); private void confirmPauseOverlayShown(bool isShown) => @@ -412,8 +421,6 @@ namespace osu.Game.Tests.Visual.Gameplay public bool PauseOverlayVisible => PauseOverlay.State.Value == Visibility.Visible; - public void ExitViaQuickExit() => PerformExit(false); - public override void OnEntering(ScreenTransitionEvent e) { base.OnEntering(e); From 974a8d520c0a630d8610447a4112ab73404c3a11 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 10 Jan 2023 15:51:22 -0800 Subject: [PATCH 061/376] Add basic toggle pause tests --- .../Visual/Gameplay/TestScenePause.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs index ca221b6b1c..f1435094b3 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs @@ -50,6 +50,22 @@ namespace osu.Game.Tests.Visual.Gameplay confirmClockRunning(true); } + [Test] + public void TestTogglePauseViaBackAction() + { + pauseViaBackAction(); + pauseViaBackAction(); + confirmPausedWithNoOverlay(); + } + + [Test] + public void TestTogglePauseViaPauseGameplayAction() + { + pauseViaPauseGameplayAction(); + pauseViaPauseGameplayAction(); + confirmPausedWithNoOverlay(); + } + [Test] public void TestPauseWithLargeOffset() { @@ -382,6 +398,7 @@ namespace osu.Game.Tests.Visual.Gameplay private void restart() => AddStep("restart", () => Player.Restart()); private void pauseViaBackAction() => AddStep("press escape", () => InputManager.Key(Key.Escape)); + private void pauseViaPauseGameplayAction() => AddStep("press middle mouse", () => InputManager.Click(MouseButton.Middle)); private void exitViaQuickExitAction() => AddStep("press ctrl-tilde", () => { From b5caa1b778bc9f663e38ba16c5f13ec6907d893f Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 10 Jan 2023 15:53:41 -0800 Subject: [PATCH 062/376] Rename pause gameplay keybind to reflect other behavior --- osu.Game/Localisation/GlobalActionKeyBindingStrings.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs index 14e0bbbced..303dbb6f46 100644 --- a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs +++ b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs @@ -155,9 +155,9 @@ namespace osu.Game.Localisation public static LocalisableString ToggleProfile => new TranslatableString(getKey(@"toggle_profile"), @"Toggle profile"); /// - /// "Pause gameplay" + /// "Pause / resume gameplay" /// - public static LocalisableString PauseGameplay => new TranslatableString(getKey(@"pause_gameplay"), @"Pause gameplay"); + public static LocalisableString PauseGameplay => new TranslatableString(getKey(@"pause_gameplay"), @"Pause / resume gameplay"); /// /// "Setup mode" From 621c75daed39de1713040bb12ece80c31586112d Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Wed, 11 Jan 2023 11:16:24 +0100 Subject: [PATCH 063/376] Add updated SkinDeserialisationTest.cs including BPM counter --- .../Archives/modified-default-20221211.osk | Bin 1650 -> 0 bytes .../Archives/modified-default-20230111.osk | Bin 0 -> 1685 bytes osu.Game.Tests/Skins/SkinDeserialisationTest.cs | 4 +++- 3 files changed, 3 insertions(+), 1 deletion(-) delete mode 100644 osu.Game.Tests/Resources/Archives/modified-default-20221211.osk create mode 100644 osu.Game.Tests/Resources/Archives/modified-default-20230111.osk diff --git a/osu.Game.Tests/Resources/Archives/modified-default-20221211.osk b/osu.Game.Tests/Resources/Archives/modified-default-20221211.osk deleted file mode 100644 index 07190db267cfcbf0abf44a5eb95b4e43bb0955d2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1650 zcmWIWW@Zs#U|`^2__41$)V#A{#{nQOh#4fpz)+l>nWvYTm-)2cFptSlz_ogQ(hG;C zH@8F=E%uturR8F1usI>|yvx0fVRLj{`=)5Kh%9yb!m&$#@A~!s>-O!N%@*d~<`;ZP z@f71Xtz$_B3H%Yh#!+{Yz0w_&)Nagm{B6aw>S`{J3j_M*Aq3^;H=}T|8F6)dAv(Ab<5aqY1+2Z>O|HRMo z=|^O*rEI>?cH!LLn%^>Fr~Wd|K|=s@#Vyw=@NZF-`xgcUZ^iK^V0J5 zvWoNbO8Yi)9WoGc{a$y}IG8)v!$>ro{pF)YewP#{EU~$@&tcLdg@3!*&fa)i^sco! zPLyHyi>sTI4dk~oU(sB!EOX<=#;UJuvQd{0EIx8BV)=H}QZEhFs+;}Rb47yQmU*3; zxb^2Bku`pHPySnM)8007O90!Ns(J=g zhwp#q^9Xfu&d)8#&r8iKDF*xC?R4Ml#|8pz?|+J_rMsWl zm~))lvSjXE-romjEqlB4%K|N7_mGKQD$Zv&{jYs`jPJ6-FWs`BcD?Mo z>hJ};;YEEHA3v|2DIJqF!&_tRvP0iLeF`i1#=MHVl)XsLTk+Vxd)4cBw&!h&K3He# zS6$HCz>?8rs8+W+%#T;OMgDgE?3d3^T}rEZTcy8FLbM=h!`nO`R$1@#Nx4(kSx<8N zxwi6P_UTOJ7%7AJpUi9clg&dUGWIrYjS*W`c1P;$wwN`hSKQX+yY+7V|8!rHmvj7` zLiXT}c7?hCHmAB{5i2!U|5{{M>HAWy?eL*^CegCp51!pC{W9-^?UU+Ts&-!(7pF|j z4$Uxlru&KS@nn&HcBOq!zI9*o`p;CpM&irNSISRyFYy;l|L6E~!T*?Flb5U8SDOAP zz97A{JjCdP==5tmp;wL=7M1Jv-49HhY?)Sm%r$}4=Va;jyU`1slUx=}XpwEm6nUVb zc%H|jBgu!ObJ62hD?{h+GUW5RfAHr^y#xbW`wc-olOm_69JfB)IpfIX@-4>uroUz? zQ^DtQ)=Hi-THF6kzeb!+_4#F^7J1$uPry5p|;f1 zQSkropj>mUWReY~TlDD8rhZwUB}upTn8nIe8{If2()ak$1dF(o?Juq^sB5Wxb@_m8!|%4ok*}6K zT=BL4fr+ohoJ~S9Uz}eBZ9jZ#L0o%@#wDL=&$irW@K=rA7M6(ANZGIP>R}+Y)!F-u0p5&E zA`H08T3}>BKqH8PmAvS>(915U9tMWSXHZ@6k_=rddg+1CIvnWvYTm-%#pVHcC5fa_;F*O{6x z&iOPeq`A$`-6GxTn0YlLx%}#-;Ij{In%z*YWEC|uF%Uk>b?^D-c-jB|R&(tu=UIDf zMePLLoRFTQ3y$+`n4z|1!$ArD1{a?Vb`52z3?ZLX1r%tg$H=jzfa z7S2h|PKWuo|4Dh+Q}}e>xz3+kGcqg}Fztl?Zxw18LVI4+{A1kKV5c;=7MF3n>IETePff23O=ZN{8+^D>6)fq8mdt@@0rgK z3CcB6{Z=ozI((yE#N3*QyX#CQ)nC~DUQ^ANv((Ao*7E=6=f}?r*U3%f$b2yUPfBjq z3Ffdp_fVaFRMl)UHxmQHD?tVZF`(0Z6EpKXLS3Bma|`nGQu9iR!G3r<{e1py1(DFpBiq9J&s4Mh+D)-^lICapXoQ^Pgx5T2Tpx@#kS)7 zl4r-xZPT_`b3BWG+rvQqpAyNhw!ONyO2y&F#=o0q{_~Z(=CeLl{z&LKFAKvPW#-HF z%v)+aF@NbQ>qTxqS5+L$KJBR-lX*e@2lJZ#Wb-vwE>y85@6afDyTf!=UggfP0O_6k zW}2M)H|4k1bgs5XebqBKfxr~T)e zZ0(N2JESMieBNrNWhlAN;_qz7nRou6rTj*z`V-ZR3=9u|nVcV(e1h}y(t}fTQj<%- z>E>u~Y&J0M*M1LAseR{k>&xjzey!Vb$7Y<#(|_c=w%lxn+EPzP!T-O5a?Q1x4b3GL z`M;}JJ}>fnx2FBVxtx|Y710f)%{nW!YUV#_Se~uMBCKsQtx}PdW9*{uQF#K90v|~&1wXM$+UkS~>U~F7)>v7wKEAi6r zC)pS53%zt~$E~{&VVP|uY#OPlryOG=WxvL&f6>1zG)rHmC9phV5rg%!_0{RmTsFLC z&y%RQcXETw!w*f5KS@T#eQ=TYx! From 1f129d4e163132c6355eb0c397c64d5bfacd8052 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Wed, 11 Jan 2023 21:20:56 +0300 Subject: [PATCH 064/376] Add failing test --- .../TestScenePlacementBeforeTrackStart.cs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 osu.Game.Rulesets.Mania.Tests/Editor/TestScenePlacementBeforeTrackStart.cs diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestScenePlacementBeforeTrackStart.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestScenePlacementBeforeTrackStart.cs new file mode 100644 index 0000000000..00dd75ceee --- /dev/null +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestScenePlacementBeforeTrackStart.cs @@ -0,0 +1,30 @@ +// 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.Containers; +using osu.Framework.Testing; +using osu.Game.Tests.Visual; +using osuTK.Input; + +namespace osu.Game.Rulesets.Mania.Tests.Editor +{ + public partial class TestScenePlacementBeforeTrackStart : EditorTestScene + { + protected override Ruleset CreateEditorRuleset() => new ManiaRuleset(); + + [Test] + public void TestPlacement() + { + AddStep("Seek to 0", () => EditorClock.Seek(0)); + AddStep("Select note", () => InputManager.Key(Key.Number2)); + AddStep("Hover negative span", () => + { + InputManager.MoveMouseTo(this.ChildrenOfType().First(x => x.Name == "Icons").Children[0]); + }); + AddStep("Click", () => InputManager.Click(MouseButton.Left)); + AddAssert("No notes placed", () => EditorBeatmap.HitObjects.All(x => x.StartTime >= 0)); + } + } +} From 1f4e0303f733265aa574d21d648d1ec1e3a5fa41 Mon Sep 17 00:00:00 2001 From: Dylan Nantz Date: Wed, 11 Jan 2023 14:13:29 -0500 Subject: [PATCH 065/376] add mania FadeIn mod configuration --- osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs | 10 +++++++--- osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs | 1 - osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs | 2 ++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs index 800973ede5..196514c7b1 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs @@ -20,8 +20,12 @@ namespace osu.Game.Rulesets.Mania.Mods protected override CoverExpandDirection ExpandDirection => CoverExpandDirection.AlongScroll; - // This could be customisable like ManiaModHidden in the future if there's any demand. - // At that point, the bindable could be moved to `ManiaModPlayfieldCover`. - public override BindableNumber Coverage { get; } = new BindableFloat(0.5f); + public override BindableNumber Coverage { get; } = new BindableFloat(0.5f) + { + Precision = 0.1f, + MinValue = 0.1f, + MaxValue = 0.7f, + Default = 0.5f, + }; } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs index 50d40249c1..8f0d5a770e 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs @@ -15,7 +15,6 @@ namespace osu.Game.Rulesets.Mania.Mods public override LocalisableString Description => @"Keys fade out before you hit them!"; public override double ScoreMultiplier => 1; - [SettingSource("Coverage", "The proportion of playfield height that notes will be hidden for.")] public override BindableNumber Coverage { get; } = new BindableFloat(0.5f) { Precision = 0.1f, diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs index 45d0184d1d..09abe8d7f4 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs @@ -6,6 +6,7 @@ using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Configuration; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mods; @@ -23,6 +24,7 @@ namespace osu.Game.Rulesets.Mania.Mods /// protected abstract CoverExpandDirection ExpandDirection { get; } + [SettingSource("Coverage", "The proportion of playfield height that notes will be hidden for.")] public abstract BindableNumber Coverage { get; } public virtual void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) From 4fce7f03bd48c2dbe091949a6c60fa4814d5b7a9 Mon Sep 17 00:00:00 2001 From: Dylan Nantz Date: Wed, 11 Jan 2023 14:14:17 -0500 Subject: [PATCH 066/376] add mania mod fadein test --- .../Mods/TestSceneManiaModFadeIn.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModFadeIn.cs diff --git a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModFadeIn.cs b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModFadeIn.cs new file mode 100644 index 0000000000..2c8c151e7f --- /dev/null +++ b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModFadeIn.cs @@ -0,0 +1,19 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Game.Rulesets.Mania.Mods; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Mania.Tests.Mods +{ + public partial class TestSceneManiaModFadeIn : ModTestScene + { + protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset(); + + [TestCase(0.5f)] + [TestCase(0.1f)] + [TestCase(0.7f)] + public void TestCoverage(float coverage) => CreateModTest(new ModTestData { Mod = new ManiaModFadeIn { Coverage = { Value = coverage } }, PassCondition = () => true }); + } +} From e23c565c8418a31bd5746eb36f112983702f876c Mon Sep 17 00:00:00 2001 From: Dylan Nantz Date: Wed, 11 Jan 2023 14:28:11 -0500 Subject: [PATCH 067/376] code quality --- osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs index 8f0d5a770e..f23cb335a5 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs @@ -4,7 +4,6 @@ using System; using System.Linq; using osu.Framework.Localisation; -using osu.Game.Configuration; using osu.Game.Rulesets.Mania.UI; using osu.Framework.Bindables; From 03ac2fd7d74b446f62328648c83e857d7aef1cd9 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 12 Jan 2023 03:33:20 +0300 Subject: [PATCH 068/376] More tests --- .../Editing/TestSceneSnappingNearZero.cs | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 osu.Game.Tests/Editing/TestSceneSnappingNearZero.cs diff --git a/osu.Game.Tests/Editing/TestSceneSnappingNearZero.cs b/osu.Game.Tests/Editing/TestSceneSnappingNearZero.cs new file mode 100644 index 0000000000..59081215ba --- /dev/null +++ b/osu.Game.Tests/Editing/TestSceneSnappingNearZero.cs @@ -0,0 +1,79 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Game.Beatmaps.ControlPoints; + +namespace osu.Game.Tests.Editing +{ + [TestFixture] + public class TestSceneSnappingNearZero + { + private readonly ControlPointInfo cpi = new ControlPointInfo(); + + [Test] + public void TestOnZero() + { + test(0, 500, 0, 0); + test(0, 500, 100, 0); + test(0, 500, 250, 500); + test(0, 500, 600, 500); + + test(0, 500, -600, 0); + } + + [Test] + public void TestAlmostOnZero() + { + test(50, 500, 0, 50); + test(50, 500, 50, 50); + test(50, 500, 100, 50); + test(50, 500, 299, 50); + test(50, 500, 300, 550); + + test(50, 500, -500, 50); + } + + [Test] + public void TestAlmostOnOne() + { + test(499, 500, -1, 499); + test(499, 500, 0, 499); + test(499, 500, 1, 499); + test(499, 500, 499, 499); + test(499, 500, 600, 499); + test(499, 500, 800, 999); + } + + [Test] + public void TestOnOne() + { + test(500, 500, -500, 0); + test(500, 500, 0, 0); + test(500, 500, 200, 0); + test(500, 500, 400, 500); + test(500, 500, 500, 500); + test(500, 500, 600, 500); + test(500, 500, 900, 1000); + } + + [Test] + public void TestNegative() + { + test(-600, 500, -600, 400); + test(-600, 500, -100, 400); + test(-600, 500, 0, 400); + test(-600, 500, 200, 400); + test(-600, 500, 400, 400); + test(-600, 500, 600, 400); + test(-600, 500, 1000, 900); + } + + private void test(double pointTime, double beatLength, double from, double expected) + { + cpi.Clear(); + cpi.Add(pointTime, new TimingControlPoint { BeatLength = beatLength }); + Assert.That(cpi.GetClosestSnappedTime(from, 1), Is.EqualTo(expected), $"From: {from}"); + } + } +} From 51e21ee6f00962c396a1987ab248c236e1865f96 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 12 Jan 2023 03:38:57 +0300 Subject: [PATCH 069/376] Make snapped time always positive --- osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index 29b7191ecf..1a15db98e4 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -183,9 +183,15 @@ namespace osu.Game.Beatmaps.ControlPoints private static double getClosestSnappedTime(TimingControlPoint timingPoint, double time, int beatDivisor) { double beatLength = timingPoint.BeatLength / beatDivisor; - int beatLengths = (int)Math.Round((time - timingPoint.Time) / beatLength, MidpointRounding.AwayFromZero); + double beats = (Math.Max(time, 0) - timingPoint.Time) / beatLength; - return timingPoint.Time + beatLengths * beatLength; + int roundedBeats = (int)Math.Round(beats, MidpointRounding.AwayFromZero); + double snappedTime = timingPoint.Time + roundedBeats * beatLength; + + if (snappedTime >= 0) + return snappedTime; + + return snappedTime + beatLength; } /// From e8029e63908fff723cdabe43152ca534a1ed3f5e Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 12 Jan 2023 03:39:27 +0300 Subject: [PATCH 070/376] Fix unrelated tests --- osu.Game.Tests/NonVisual/ClosestBeatDivisorTest.cs | 8 ++++---- osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/NonVisual/ClosestBeatDivisorTest.cs b/osu.Game.Tests/NonVisual/ClosestBeatDivisorTest.cs index 6f3fe875e3..8ebf34b1ca 100644 --- a/osu.Game.Tests/NonVisual/ClosestBeatDivisorTest.cs +++ b/osu.Game.Tests/NonVisual/ClosestBeatDivisorTest.cs @@ -17,7 +17,7 @@ namespace osu.Game.Tests.NonVisual public void TestExactDivisors() { var cpi = new ControlPointInfo(); - cpi.Add(-1000, new TimingControlPoint { BeatLength = 1000 }); + cpi.Add(0, new TimingControlPoint { BeatLength = 1000 }); double[] divisors = { 3, 1, 16, 12, 8, 6, 4, 3, 2, 1 }; @@ -47,7 +47,7 @@ namespace osu.Game.Tests.NonVisual public void TestExactDivisorsHighBPMStream() { var cpi = new ControlPointInfo(); - cpi.Add(-50, new TimingControlPoint { BeatLength = 50 }); // 1200 BPM 1/4 (limit testing) + cpi.Add(0, new TimingControlPoint { BeatLength = 50 }); // 1200 BPM 1/4 (limit testing) // A 1/4 stream should land on 1/1, 1/2 and 1/4 divisors. double[] divisors = { 4, 4, 4, 4, 4, 4, 4, 4 }; @@ -60,7 +60,7 @@ namespace osu.Game.Tests.NonVisual public void TestApproximateDivisors() { var cpi = new ControlPointInfo(); - cpi.Add(-1000, new TimingControlPoint { BeatLength = 1000 }); + cpi.Add(0, new TimingControlPoint { BeatLength = 1000 }); double[] divisors = { 3.03d, 0.97d, 14, 13, 7.94d, 6.08d, 3.93d, 2.96d, 2.02d, 64 }; double[] closestDivisors = { 3, 1, 16, 12, 8, 6, 4, 3, 2, 1 }; @@ -68,7 +68,7 @@ namespace osu.Game.Tests.NonVisual assertClosestDivisors(divisors, closestDivisors, cpi); } - private void assertClosestDivisors(IReadOnlyList divisors, IReadOnlyList closestDivisors, ControlPointInfo cpi, double step = 1) + private static void assertClosestDivisors(IReadOnlyList divisors, IReadOnlyList closestDivisors, ControlPointInfo cpi, double step = 1) { List hitobjects = new List(); double offset = cpi.TimingPoints[0].Time; diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs index 70118e0b67..b396b382ff 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs @@ -144,7 +144,7 @@ namespace osu.Game.Tests.Visual.Editing double lastStarRating = 0; double lastLength = 0; - AddStep("Add timing point", () => EditorBeatmap.ControlPointInfo.Add(500, new TimingControlPoint())); + AddStep("Add timing point", () => EditorBeatmap.ControlPointInfo.Add(200, new TimingControlPoint { BeatLength = 600 })); AddStep("Change to placement mode", () => InputManager.Key(Key.Number2)); AddStep("Move to playfield", () => InputManager.MoveMouseTo(Game.ScreenSpaceDrawQuad.Centre)); AddStep("Place single hitcircle", () => InputManager.Click(MouseButton.Left)); From 4439698867b7f9b98d862d49903524d244edb215 Mon Sep 17 00:00:00 2001 From: Ruki Date: Thu, 12 Jan 2023 13:19:03 +0100 Subject: [PATCH 071/376] Update osu.Game/Screens/Play/HUD/ArgonSongProgress.cs --- osu.Game/Screens/Play/HUD/ArgonSongProgress.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs b/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs index c36f881ec2..e5ee42e72a 100644 --- a/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs +++ b/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs @@ -54,8 +54,6 @@ namespace osu.Game.Screens.Play.HUD Origin = Anchor.BottomLeft, Anchor = Anchor.BottomLeft, RelativeSizeAxes = Axes.X, - Masking = true, - CornerRadius = 5, }, bar = new ArgonSongProgressBar(bar_height) { From 403ca05e5e61aeecb19ce9afeb59ca91bf2a49db Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Fri, 13 Jan 2023 00:52:14 +0100 Subject: [PATCH 072/376] Enable nullability for song select --- .../Multiplayer/MultiplayerMatchSongSelect.cs | 2 + .../OnlinePlay/OnlinePlaySongSelect.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 155 ++++++++++-------- 3 files changed, 87 insertions(+), 72 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs index 873a1b0d50..6a4ce7aff5 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; @@ -105,6 +106,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer Schedule(() => { + Debug.Assert(Carousel != null); Carousel.AllowSelection = true; }); }); diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs index b9d8912170..e0ae437d49 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs @@ -173,7 +173,7 @@ namespace osu.Game.Screens.OnlinePlay IsValidMod = IsValidMod }; - protected override IEnumerable<(FooterButton, OverlayContainer)> CreateFooterButtons() + protected override IEnumerable<(FooterButton, OverlayContainer?)> CreateFooterButtons() { var buttons = base.CreateFooterButtons().ToList(); buttons.Insert(buttons.FindIndex(b => b.Item1 is FooterButtonMods) + 1, (new FooterButtonFreeMods { Current = FreeMods }, freeModSelectOverlay)); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index f4804c6a6c..6826dffd5f 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.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.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; @@ -36,7 +34,6 @@ using osu.Framework.Input.Bindings; using osu.Game.Collections; using osu.Game.Graphics.UserInterface; using System.Diagnostics; -using JetBrains.Annotations; using osu.Game.Screens.Play; using osu.Game.Skinning; @@ -49,7 +46,7 @@ namespace osu.Game.Screens.Select protected const float BACKGROUND_BLUR = 20; private const float left_area_padding = 20; - public FilterControl FilterControl { get; private set; } + public FilterControl FilterControl { get; private set; } = null!; /// /// Whether this song select instance should take control of the global track, @@ -64,18 +61,18 @@ namespace osu.Game.Screens.Select /// /// Can be null if is false. /// - protected BeatmapOptionsOverlay BeatmapOptions { get; private set; } + protected BeatmapOptionsOverlay BeatmapOptions { get; private set; } = null!; /// /// Can be null if is false. /// - protected Footer Footer { get; private set; } + protected Footer? Footer { get; private set; } /// /// Contains any panel which is triggered by a footer button. /// Helps keep them located beneath the footer itself. /// - protected Container FooterPanels { get; private set; } + protected Container FooterPanels { get; private set; } = null!; /// /// Whether entering editor mode should be allowed. @@ -85,50 +82,49 @@ namespace osu.Game.Screens.Select public bool BeatmapSetsLoaded => IsLoaded && Carousel?.BeatmapSetsLoaded == true; [Resolved] - private Bindable> selectedMods { get; set; } + private Bindable> selectedMods { get; set; } = null!; - protected BeatmapCarousel Carousel { get; private set; } + protected BeatmapCarousel? Carousel { get; private set; } - private ParallaxContainer wedgeBackground; + private ParallaxContainer wedgeBackground = null!; - protected Container LeftArea { get; private set; } + protected Container LeftArea { get; private set; } = null!; - private BeatmapInfoWedge beatmapInfoWedge; - - [Resolved(canBeNull: true)] - private IDialogOverlay dialogOverlay { get; set; } + private BeatmapInfoWedge beatmapInfoWedge = null!; [Resolved] - private BeatmapManager beatmaps { get; set; } + private IDialogOverlay? dialogOverlay { get; set; } - protected ModSelectOverlay ModSelect { get; private set; } + [Resolved] + private BeatmapManager beatmaps { get; set; } = null!; - protected Sample SampleConfirm { get; private set; } + protected ModSelectOverlay ModSelect { get; private set; } = null!; - private Sample sampleChangeDifficulty; - private Sample sampleChangeBeatmap; + protected Sample? SampleConfirm { get; private set; } - private Container carouselContainer; + private Sample sampleChangeDifficulty = null!; + private Sample sampleChangeBeatmap = null!; - protected BeatmapDetailArea BeatmapDetails { get; private set; } + private Container carouselContainer = null!; - private FooterButtonOptions beatmapOptionsButton; + protected BeatmapDetailArea BeatmapDetails { get; private set; } = null!; + + private FooterButtonOptions beatmapOptionsButton = null!; private readonly Bindable decoupledRuleset = new Bindable(); private double audioFeedbackLastPlaybackTime; - [CanBeNull] - private IDisposable modSelectOverlayRegistration; + private IDisposable? modSelectOverlayRegistration; [Resolved] - private MusicController music { get; set; } + private MusicController? music { get; set; } - [Resolved(CanBeNull = true)] - internal IOverlayManager OverlayManager { get; private set; } + [Resolved] + internal IOverlayManager? OverlayManager { get; private set; } [BackgroundDependencyLoader(true)] - private void load(AudioManager audio, OsuColour colours, ManageCollectionsDialog manageCollectionsDialog, DifficultyRecommender recommender) + private void load(AudioManager audio, OsuColour colours, ManageCollectionsDialog? manageCollectionsDialog, DifficultyRecommender? recommender) { // initial value transfer is required for FilterControl (it uses our re-cached bindables in its async load for the initial filter). transferRulesetValue(); @@ -273,7 +269,7 @@ namespace osu.Game.Screens.Select BeatmapOptions = new BeatmapOptionsOverlay(), } }, - Footer = new Footer(), + Footer = new Footer() }); } @@ -318,16 +314,20 @@ namespace osu.Game.Screens.Select /// Creates the buttons to be displayed in the footer. /// /// A set of and an optional which the button opens when pressed. - protected virtual IEnumerable<(FooterButton, OverlayContainer)> CreateFooterButtons() => new (FooterButton, OverlayContainer)[] + protected virtual IEnumerable<(FooterButton, OverlayContainer?)> CreateFooterButtons() { - (new FooterButtonMods { Current = Mods }, ModSelect), - (new FooterButtonRandom + Debug.Assert(Carousel != null); + return new (FooterButton, OverlayContainer?)[] { - NextRandom = () => Carousel.SelectNextRandom(), - PreviousRandom = Carousel.SelectPreviousRandom - }, null), - (beatmapOptionsButton = new FooterButtonOptions(), BeatmapOptions) - }; + (new FooterButtonMods { Current = Mods }, ModSelect), + (new FooterButtonRandom + { + NextRandom = () => Carousel.SelectNextRandom(), + PreviousRandom = Carousel.SelectPreviousRandom + }, null), + (beatmapOptionsButton = new FooterButtonOptions(), BeatmapOptions) + }; + } protected virtual ModSelectOverlay CreateModSelectOverlay() => new SoloModSelectOverlay(); @@ -336,10 +336,11 @@ namespace osu.Game.Screens.Select // if not the current screen, we want to get carousel in a good presentation state before displaying (resume or enter). bool shouldDebounce = this.IsCurrentScreen(); + Debug.Assert(Carousel != null); Carousel.Filter(criteria, shouldDebounce); } - private DependencyContainer dependencies; + private DependencyContainer dependencies = null!; protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) { @@ -357,7 +358,7 @@ namespace osu.Game.Screens.Select /// protected abstract BeatmapDetailArea CreateBeatmapDetailArea(); - public void Edit(BeatmapInfo beatmapInfo = null) + public void Edit(BeatmapInfo? beatmapInfo = null) { if (!AllowEditing) throw new InvalidOperationException($"Attempted to edit when {nameof(AllowEditing)} is disabled"); @@ -372,8 +373,10 @@ namespace osu.Game.Screens.Select /// An optional beatmap to override the current carousel selection. /// An optional ruleset to override the current carousel selection. /// An optional custom action to perform instead of . - public void FinaliseSelection(BeatmapInfo beatmapInfo = null, RulesetInfo ruleset = null, Action customStartAction = null) + public void FinaliseSelection(BeatmapInfo? beatmapInfo = null, RulesetInfo? ruleset = null, Action? customStartAction = null) { + Debug.Assert(Carousel != null); + // This is very important as we have not yet bound to screen-level bindables before the carousel load is completed. if (!Carousel.BeatmapSetsLoaded) { @@ -419,43 +422,44 @@ namespace osu.Game.Screens.Select /// If a resultant action occurred that takes the user away from SongSelect. protected abstract bool OnStart(); - private ScheduledDelegate selectionChangedDebounce; + private ScheduledDelegate? selectionChangedDebounce; - private void updateCarouselSelection(ValueChangedEvent e = null) + private void updateCarouselSelection(ValueChangedEvent? e = null) { var beatmap = e?.NewValue ?? Beatmap.Value; if (beatmap is DummyWorkingBeatmap || !this.IsCurrentScreen()) return; Logger.Log($"Song select working beatmap updated to {beatmap}"); - if (!Carousel.SelectBeatmap(beatmap.BeatmapInfo, false)) + Debug.Assert(Carousel != null); + + if (Carousel.SelectBeatmap(beatmap.BeatmapInfo, false)) return; + + // A selection may not have been possible with filters applied. + + // There was possibly a ruleset mismatch. This is a case we can help things along by updating the game-wide ruleset to match. + if (!beatmap.BeatmapInfo.Ruleset.Equals(decoupledRuleset.Value)) { - // A selection may not have been possible with filters applied. - - // There was possibly a ruleset mismatch. This is a case we can help things along by updating the game-wide ruleset to match. - if (!beatmap.BeatmapInfo.Ruleset.Equals(decoupledRuleset.Value)) - { - Ruleset.Value = beatmap.BeatmapInfo.Ruleset; - transferRulesetValue(); - } - - // Even if a ruleset mismatch was not the cause (ie. a text filter is applied), - // we still want to temporarily show the new beatmap, bypassing filters. - // This will be undone the next time the user changes the filter. - var criteria = FilterControl.CreateCriteria(); - criteria.SelectedBeatmapSet = beatmap.BeatmapInfo.BeatmapSet; - Carousel.Filter(criteria); - - Carousel.SelectBeatmap(beatmap.BeatmapInfo); + Ruleset.Value = beatmap.BeatmapInfo.Ruleset; + transferRulesetValue(); } + + // Even if a ruleset mismatch was not the cause (ie. a text filter is applied), + // we still want to temporarily show the new beatmap, bypassing filters. + // This will be undone the next time the user changes the filter. + var criteria = FilterControl.CreateCriteria(); + criteria.SelectedBeatmapSet = beatmap.BeatmapInfo.BeatmapSet; + Carousel.Filter(criteria); + + Carousel.SelectBeatmap(beatmap.BeatmapInfo); } // We need to keep track of the last selected beatmap ignoring debounce to play the correct selection sounds. - private BeatmapInfo beatmapInfoPrevious; - private BeatmapInfo beatmapInfoNoDebounce; - private RulesetInfo rulesetNoDebounce; + private BeatmapInfo? beatmapInfoPrevious; + private BeatmapInfo? beatmapInfoNoDebounce; + private RulesetInfo? rulesetNoDebounce; - private void updateSelectedBeatmap(BeatmapInfo beatmapInfo) + private void updateSelectedBeatmap(BeatmapInfo? beatmapInfo) { if (beatmapInfo == null && beatmapInfoNoDebounce == null) return; @@ -467,7 +471,7 @@ namespace osu.Game.Screens.Select performUpdateSelected(); } - private void updateSelectedRuleset(RulesetInfo ruleset) + private void updateSelectedRuleset(RulesetInfo? ruleset) { if (ruleset == null && rulesetNoDebounce == null) return; @@ -485,7 +489,7 @@ namespace osu.Game.Screens.Select private void performUpdateSelected() { var beatmap = beatmapInfoNoDebounce; - var ruleset = rulesetNoDebounce; + RulesetInfo? ruleset = rulesetNoDebounce; selectionChangedDebounce?.Cancel(); @@ -518,6 +522,7 @@ namespace osu.Game.Screens.Select if (transferRulesetValue()) { + Debug.Assert(Carousel != null); // transferRulesetValue() may trigger a re-filter. If the current selection does not match the new ruleset, we want to switch away from it. // The default logic on WorkingBeatmap change is to switch to a matching ruleset (see workingBeatmapChanged()), but we don't want that here. // We perform an early selection attempt and clear out the beatmap selection to avoid a second ruleset change (revert). @@ -604,6 +609,7 @@ namespace osu.Game.Screens.Select ModSelect.SelectedMods.Disabled = false; ModSelect.SelectedMods.BindTo(selectedMods); + Debug.Assert(Carousel != null); Carousel.AllowSelection = true; BeatmapDetails.Refresh(); @@ -620,6 +626,7 @@ namespace osu.Game.Screens.Select { // restart playback on returning to song select, regardless. // not sure this should be a permanent thing (we may want to leave a user pause paused even on returning) + Debug.Assert(music != null); music.ResetTrackAdjustments(); music.Play(requestedByUser: true); } @@ -665,6 +672,7 @@ namespace osu.Game.Screens.Select BeatmapOptions.Hide(); + Debug.Assert(Carousel != null); Carousel.AllowSelection = false; endLooping(); @@ -694,6 +702,8 @@ namespace osu.Game.Screens.Select isHandlingLooping = true; ensureTrackLooping(Beatmap.Value, TrackChangeDirection.None); + + Debug.Assert(music != null); music.TrackChanged += ensureTrackLooping; } @@ -703,6 +713,7 @@ namespace osu.Game.Screens.Select if (!isHandlingLooping) return; + Debug.Assert(music != null); music.CurrentTrack.Looping = isHandlingLooping = false; music.TrackChanged -= ensureTrackLooping; @@ -763,7 +774,7 @@ namespace osu.Game.Screens.Select } } - private readonly WeakReference lastTrack = new WeakReference(null); + private readonly WeakReference lastTrack = new WeakReference(null); /// /// Ensures some music is playing for the current track. @@ -774,6 +785,7 @@ namespace osu.Game.Screens.Select if (!ControlGlobalMusic) return; + Debug.Assert(music != null); ITrack track = music.CurrentTrack; bool isNewTrack = !lastTrack.TryGetTarget(out var last) || last != track; @@ -791,6 +803,7 @@ namespace osu.Game.Screens.Select { bindBindables(); + Debug.Assert(Carousel != null); Carousel.AllowSelection = true; // If a selection was already obtained, do not attempt to update the selected beatmap. @@ -868,14 +881,14 @@ namespace osu.Game.Screens.Select return true; } - private void delete(BeatmapSetInfo beatmap) + private void delete(BeatmapSetInfo? beatmap) { if (beatmap == null) return; dialogOverlay?.Push(new BeatmapDeleteDialog(beatmap)); } - private void clearScores(BeatmapInfo beatmapInfo) + private void clearScores(BeatmapInfo? beatmapInfo) { if (beatmapInfo == null) return; @@ -950,7 +963,7 @@ namespace osu.Game.Screens.Select private partial class ResetScrollContainer : Container { - private readonly Action onHoverAction; + private readonly Action? onHoverAction; public ResetScrollContainer(Action onHoverAction) { From 653376f5f2814476a3a29da545896d8c23badec7 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Fri, 13 Jan 2023 09:32:36 +0100 Subject: [PATCH 073/376] Fix test failures --- osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index cfee02dfb8..97ffd896c6 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -1151,7 +1151,7 @@ namespace osu.Game.Tests.Visual.SongSelect public WorkingBeatmap CurrentBeatmap => Beatmap.Value; public IWorkingBeatmap CurrentBeatmapDetailsBeatmap => BeatmapDetails.Beatmap; - public new BeatmapCarousel Carousel => base.Carousel; + public new BeatmapCarousel Carousel => base.Carousel!; public new ModSelectOverlay ModSelect => base.ModSelect; public new void PresentScore(ScoreInfo score) => base.PresentScore(score); From a6b6fb864eaa673e9f5cd325a1965624fb482973 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Fri, 13 Jan 2023 13:10:29 +0100 Subject: [PATCH 074/376] Make carousel non nullable and ensure pre load usages of methods that reference it are protected against failure --- .../SongSelect/TestScenePlaySongSelect.cs | 2 +- .../Multiplayer/MultiplayerMatchSongSelect.cs | 2 -- osu.Game/Screens/Select/SongSelect.cs | 29 +++++++------------ 3 files changed, 11 insertions(+), 22 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 97ffd896c6..cfee02dfb8 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -1151,7 +1151,7 @@ namespace osu.Game.Tests.Visual.SongSelect public WorkingBeatmap CurrentBeatmap => Beatmap.Value; public IWorkingBeatmap CurrentBeatmapDetailsBeatmap => BeatmapDetails.Beatmap; - public new BeatmapCarousel Carousel => base.Carousel!; + public new BeatmapCarousel Carousel => base.Carousel; public new ModSelectOverlay ModSelect => base.ModSelect; public new void PresentScore(ScoreInfo score) => base.PresentScore(score); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs index 6a4ce7aff5..873a1b0d50 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; @@ -106,7 +105,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer Schedule(() => { - Debug.Assert(Carousel != null); Carousel.AllowSelection = true; }); }); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 6826dffd5f..ef5827fad7 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -79,12 +79,12 @@ namespace osu.Game.Screens.Select /// public virtual bool AllowEditing => true; - public bool BeatmapSetsLoaded => IsLoaded && Carousel?.BeatmapSetsLoaded == true; + public bool BeatmapSetsLoaded => IsLoaded && Carousel.BeatmapSetsLoaded; [Resolved] private Bindable> selectedMods { get; set; } = null!; - protected BeatmapCarousel? Carousel { get; private set; } + protected BeatmapCarousel Carousel { get; private set; } = null!; private ParallaxContainer wedgeBackground = null!; @@ -127,7 +127,7 @@ namespace osu.Game.Screens.Select private void load(AudioManager audio, OsuColour colours, ManageCollectionsDialog? manageCollectionsDialog, DifficultyRecommender? recommender) { // initial value transfer is required for FilterControl (it uses our re-cached bindables in its async load for the initial filter). - transferRulesetValue(); + transferRulesetValue(false); LoadComponentAsync(Carousel = new BeatmapCarousel { @@ -314,10 +314,8 @@ namespace osu.Game.Screens.Select /// Creates the buttons to be displayed in the footer. /// /// A set of and an optional which the button opens when pressed. - protected virtual IEnumerable<(FooterButton, OverlayContainer?)> CreateFooterButtons() - { - Debug.Assert(Carousel != null); - return new (FooterButton, OverlayContainer?)[] + protected virtual IEnumerable<(FooterButton, OverlayContainer?)> CreateFooterButtons() => + new (FooterButton, OverlayContainer?)[] { (new FooterButtonMods { Current = Mods }, ModSelect), (new FooterButtonRandom @@ -327,7 +325,6 @@ namespace osu.Game.Screens.Select }, null), (beatmapOptionsButton = new FooterButtonOptions(), BeatmapOptions) }; - } protected virtual ModSelectOverlay CreateModSelectOverlay() => new SoloModSelectOverlay(); @@ -336,7 +333,6 @@ namespace osu.Game.Screens.Select // if not the current screen, we want to get carousel in a good presentation state before displaying (resume or enter). bool shouldDebounce = this.IsCurrentScreen(); - Debug.Assert(Carousel != null); Carousel.Filter(criteria, shouldDebounce); } @@ -375,8 +371,6 @@ namespace osu.Game.Screens.Select /// An optional custom action to perform instead of . public void FinaliseSelection(BeatmapInfo? beatmapInfo = null, RulesetInfo? ruleset = null, Action? customStartAction = null) { - Debug.Assert(Carousel != null); - // This is very important as we have not yet bound to screen-level bindables before the carousel load is completed. if (!Carousel.BeatmapSetsLoaded) { @@ -431,8 +425,6 @@ namespace osu.Game.Screens.Select Logger.Log($"Song select working beatmap updated to {beatmap}"); - Debug.Assert(Carousel != null); - if (Carousel.SelectBeatmap(beatmap.BeatmapInfo, false)) return; // A selection may not have been possible with filters applied. @@ -522,7 +514,6 @@ namespace osu.Game.Screens.Select if (transferRulesetValue()) { - Debug.Assert(Carousel != null); // transferRulesetValue() may trigger a re-filter. If the current selection does not match the new ruleset, we want to switch away from it. // The default logic on WorkingBeatmap change is to switch to a matching ruleset (see workingBeatmapChanged()), but we don't want that here. // We perform an early selection attempt and clear out the beatmap selection to avoid a second ruleset change (revert). @@ -609,7 +600,6 @@ namespace osu.Game.Screens.Select ModSelect.SelectedMods.Disabled = false; ModSelect.SelectedMods.BindTo(selectedMods); - Debug.Assert(Carousel != null); Carousel.AllowSelection = true; BeatmapDetails.Refresh(); @@ -672,7 +662,6 @@ namespace osu.Game.Screens.Select BeatmapOptions.Hide(); - Debug.Assert(Carousel != null); Carousel.AllowSelection = false; endLooping(); @@ -803,7 +792,6 @@ namespace osu.Game.Screens.Select { bindBindables(); - Debug.Assert(Carousel != null); Carousel.AllowSelection = true; // If a selection was already obtained, do not attempt to update the selected beatmap. @@ -867,7 +855,7 @@ namespace osu.Game.Screens.Select /// Will immediately run filter operations if required. /// /// Whether a transfer occurred. - private bool transferRulesetValue() + private bool transferRulesetValue(bool carouselLoaded = true) { if (decoupledRuleset.Value?.Equals(Ruleset.Value) == true) return false; @@ -875,9 +863,12 @@ namespace osu.Game.Screens.Select Logger.Log($"decoupled ruleset transferred (\"{decoupledRuleset.Value}\" -> \"{Ruleset.Value}\")"); rulesetNoDebounce = decoupledRuleset.Value = Ruleset.Value; + // We don't want to declare the carousel as nullable, so this check allows us to avoid running the carousel flush during the loading process + if (!carouselLoaded) return true; + // if we have a pending filter operation, we want to run it now. // it could change selection (ie. if the ruleset has been changed). - Carousel?.FlushPendingFilterOperations(); + Carousel.FlushPendingFilterOperations(); return true; } From 0b5c89d01fde788848440d474b3d50de8e30383e Mon Sep 17 00:00:00 2001 From: integer <7279624+integerrr@users.noreply.github.com> Date: Fri, 13 Jan 2023 23:07:21 +0000 Subject: [PATCH 075/376] revert additions to `SessionStatics` --- osu.Game.Tests/NonVisual/SessionStaticsTest.cs | 6 ------ osu.Game/Configuration/SessionStatics.cs | 4 ---- .../Screens/Play/HUD/PlayerSettingsOverlay.cs | 15 --------------- 3 files changed, 25 deletions(-) diff --git a/osu.Game.Tests/NonVisual/SessionStaticsTest.cs b/osu.Game.Tests/NonVisual/SessionStaticsTest.cs index 499c0e5d34..5c8254b947 100644 --- a/osu.Game.Tests/NonVisual/SessionStaticsTest.cs +++ b/osu.Game.Tests/NonVisual/SessionStaticsTest.cs @@ -24,16 +24,12 @@ namespace osu.Game.Tests.NonVisual sessionStatics.SetValue(Static.MutedAudioNotificationShownOnce, true); sessionStatics.SetValue(Static.LowBatteryNotificationShownOnce, true); sessionStatics.SetValue(Static.LastHoverSoundPlaybackTime, (double?)1d); - sessionStatics.SetValue(Static.ReplayPlaybackSettingExpanded, false); - sessionStatics.SetValue(Static.ReplayVisualSettingsExpanded, true); sessionStatics.SetValue(Static.SeasonalBackgrounds, new APISeasonalBackgrounds { EndDate = new DateTimeOffset(2022, 1, 1, 0, 0, 0, TimeSpan.Zero) }); Assert.IsFalse(sessionStatics.GetBindable(Static.LoginOverlayDisplayed).IsDefault); Assert.IsFalse(sessionStatics.GetBindable(Static.MutedAudioNotificationShownOnce).IsDefault); Assert.IsFalse(sessionStatics.GetBindable(Static.LowBatteryNotificationShownOnce).IsDefault); Assert.IsFalse(sessionStatics.GetBindable(Static.LastHoverSoundPlaybackTime).IsDefault); - Assert.IsFalse(sessionStatics.GetBindable(Static.ReplayPlaybackSettingExpanded).IsDefault); - Assert.IsFalse(sessionStatics.GetBindable(Static.ReplayVisualSettingsExpanded).IsDefault); Assert.IsFalse(sessionStatics.GetBindable(Static.SeasonalBackgrounds).IsDefault); sessionStatics.ResetAfterInactivity(); @@ -43,8 +39,6 @@ namespace osu.Game.Tests.NonVisual Assert.IsTrue(sessionStatics.GetBindable(Static.LowBatteryNotificationShownOnce).IsDefault); // some statics should not reset despite inactivity. Assert.IsFalse(sessionStatics.GetBindable(Static.LastHoverSoundPlaybackTime).IsDefault); - Assert.IsFalse(sessionStatics.GetBindable(Static.ReplayPlaybackSettingExpanded).IsDefault); - Assert.IsFalse(sessionStatics.GetBindable(Static.ReplayVisualSettingsExpanded).IsDefault); Assert.IsFalse(sessionStatics.GetBindable(Static.SeasonalBackgrounds).IsDefault); } } diff --git a/osu.Game/Configuration/SessionStatics.cs b/osu.Game/Configuration/SessionStatics.cs index f08658f182..12a30a0c84 100644 --- a/osu.Game/Configuration/SessionStatics.cs +++ b/osu.Game/Configuration/SessionStatics.cs @@ -20,8 +20,6 @@ namespace osu.Game.Configuration SetDefault(Static.MutedAudioNotificationShownOnce, false); SetDefault(Static.LowBatteryNotificationShownOnce, false); SetDefault(Static.LastHoverSoundPlaybackTime, (double?)null); - SetDefault(Static.ReplayPlaybackSettingExpanded, true); - SetDefault(Static.ReplayVisualSettingsExpanded, false); SetDefault(Static.SeasonalBackgrounds, null); } @@ -44,8 +42,6 @@ namespace osu.Game.Configuration LoginOverlayDisplayed, MutedAudioNotificationShownOnce, LowBatteryNotificationShownOnce, - ReplayPlaybackSettingExpanded, - ReplayVisualSettingsExpanded, /// /// Info about seasonal backgrounds available fetched from API - see . diff --git a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs index c4f07f77cd..1edb227a75 100644 --- a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs +++ b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs @@ -3,15 +3,12 @@ #nullable disable -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; using osuTK; using osu.Game.Screens.Play.PlayerSettings; using osuTK.Input; -using osu.Game.Configuration; -using osu.Framework.Allocation; namespace osu.Game.Screens.Play.HUD { @@ -19,9 +16,6 @@ namespace osu.Game.Screens.Play.HUD { private const int fade_duration = 200; - private Bindable playbackMenuExpanded; - - private Bindable visualMenuExpanded; public bool ReplayLoaded; @@ -54,15 +48,6 @@ namespace osu.Game.Screens.Play.HUD }; } - [BackgroundDependencyLoader] - private void load(SessionStatics statics) - { - playbackMenuExpanded = statics.GetBindable(Static.ReplayPlaybackSettingExpanded); - visualMenuExpanded = statics.GetBindable(Static.ReplayVisualSettingsExpanded); - - PlaybackSettings.Expanded.BindTo(playbackMenuExpanded); - VisualSettings.Expanded.BindTo(visualMenuExpanded); - } protected override void PopIn() => this.FadeIn(fade_duration); protected override void PopOut() => this.FadeOut(fade_duration); From c3c1d77e8e8d0ccab211e461c84b73062c7aeece Mon Sep 17 00:00:00 2001 From: integer <7279624+integerrr@users.noreply.github.com> Date: Fri, 13 Jan 2023 23:07:59 +0000 Subject: [PATCH 076/376] make `PlayerSettingsGroup` expand on hover --- .../Screens/Play/HUD/PlayerSettingsOverlay.cs | 6 ++--- .../PlayerSettings/PlayerSettingsGroup.cs | 24 +++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs index 1edb227a75..019ba53a5e 100644 --- a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs +++ b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs @@ -16,7 +16,6 @@ namespace osu.Game.Screens.Play.HUD { private const int fade_duration = 200; - public bool ReplayLoaded; public readonly PlaybackSettings PlaybackSettings; @@ -42,13 +41,12 @@ namespace osu.Game.Screens.Play.HUD { //CollectionSettings = new CollectionSettings(), //DiscussionSettings = new DiscussionSettings(), - PlaybackSettings = new PlaybackSettings(), - VisualSettings = new VisualSettings() + PlaybackSettings = new PlaybackSettings { Expanded = { Value = false } }, + VisualSettings = new VisualSettings { Expanded = { Value = false } } } }; } - protected override void PopIn() => this.FadeIn(fade_duration); protected override void PopOut() => this.FadeOut(fade_duration); diff --git a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs index 6c6f62a8ac..63e081b2ea 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs @@ -4,6 +4,7 @@ #nullable disable using osu.Framework.Input.Events; +using osu.Framework.Threading; using osu.Game.Overlays; namespace osu.Game.Screens.Play.PlayerSettings @@ -15,12 +16,35 @@ namespace osu.Game.Screens.Play.PlayerSettings { } + private ScheduledDelegate hoverExpandEvent; + protected override bool OnHover(HoverEvent e) { + updateHoverExpansion(); base.OnHover(e); // Importantly, return true to correctly take focus away from PlayerLoader. return true; } + + protected override void OnHoverLost(HoverLostEvent e) + { + if (hoverExpandEvent == null) return; + + hoverExpandEvent?.Cancel(); + hoverExpandEvent = null; + + Expanded.Value = false; + + base.OnHoverLost(e); + } + + private void updateHoverExpansion() + { + hoverExpandEvent?.Cancel(); + + if (IsHovered && !Expanded.Value) + hoverExpandEvent = Scheduler.AddDelayed(() => Expanded.Value = true, 0); + } } } From 9e7ecbf4a14ebf97459677b128ef70528d0115e2 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 02:41:11 +0300 Subject: [PATCH 077/376] Adapt to changes in base class --- osu.Game/Overlays/Comments/CommentsContainer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 98c186b273..08542bbcea 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -429,15 +429,15 @@ namespace osu.Game.Overlays.Comments protected override void OnCommit(string text) { - CommitButton.IsLoadingSpinnerShown = true; + ShowLoadingSpinner = true; CommentPostRequest req = new CommentPostRequest(CommentableType.Value, CommentableId.Value, text); req.Failure += _ => Schedule(() => { - CommitButton.IsLoadingSpinnerShown = false; + ShowLoadingSpinner = false; }); req.Success += cb => Schedule(() => { - CommitButton.IsLoadingSpinnerShown = false; + ShowLoadingSpinner = false; Current.Value = string.Empty; OnPost?.Invoke(cb); }); From bb8bcd7248153a5bf1ae2c96dcaf0e93bda0502e Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 02:50:30 +0300 Subject: [PATCH 078/376] Move avatar update bind to LoadComplete --- osu.Game/Overlays/Comments/CommentsContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 08542bbcea..9446857f5e 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -183,12 +183,12 @@ namespace osu.Game.Overlays.Comments }); User.BindTo(api.LocalUser); - User.BindValueChanged(e => avatar.User = e.NewValue); } protected override void LoadComplete() { User.BindValueChanged(_ => refetchComments()); + User.BindValueChanged(e => avatar.User = e.NewValue); Sort.BindValueChanged(_ => refetchComments(), true); base.LoadComplete(); } From 2831db53f74088e1fb08e39cf51ded52cd5d76e9 Mon Sep 17 00:00:00 2001 From: integer <7279624+integerrr@users.noreply.github.com> Date: Sat, 14 Jan 2023 14:19:02 +0000 Subject: [PATCH 079/376] fix wrong control flow on hover lost --- .../Play/PlayerSettings/PlayerSettingsGroup.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs index 63e081b2ea..f4769cd417 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs @@ -29,12 +29,13 @@ namespace osu.Game.Screens.Play.PlayerSettings protected override void OnHoverLost(HoverLostEvent e) { - if (hoverExpandEvent == null) return; + if (hoverExpandEvent != null) + { + hoverExpandEvent?.Cancel(); + hoverExpandEvent = null; - hoverExpandEvent?.Cancel(); - hoverExpandEvent = null; - - Expanded.Value = false; + Expanded.Value = false; + } base.OnHoverLost(e); } From fbb674d8e9d809b9a5154525d96e36685e928fac Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 20:15:19 +0300 Subject: [PATCH 080/376] Rename parent comment id field --- osu.Game/Online/API/Requests/CommentPostRequest.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/API/Requests/CommentPostRequest.cs b/osu.Game/Online/API/Requests/CommentPostRequest.cs index 7012d479bd..45e5eb1a94 100644 --- a/osu.Game/Online/API/Requests/CommentPostRequest.cs +++ b/osu.Game/Online/API/Requests/CommentPostRequest.cs @@ -12,14 +12,14 @@ namespace osu.Game.Online.API.Requests public readonly CommentableType Commentable; public readonly long CommentableId; public readonly string Message; - public readonly long? ReplyTo; + public readonly long? ParentCommentId; - public CommentPostRequest(CommentableType commentable, long commentableId, string message, long? replyTo = null) + public CommentPostRequest(CommentableType commentable, long commentableId, string message, long? parentCommentId = null) { Commentable = commentable; CommentableId = commentableId; Message = message; - ReplyTo = replyTo; + ParentCommentId = parentCommentId; } protected override WebRequest CreateWebRequest() @@ -30,8 +30,8 @@ namespace osu.Game.Online.API.Requests req.AddParameter(@"comment[commentable_type]", Commentable.ToString().ToLowerInvariant()); req.AddParameter(@"comment[commentable_id]", $"{CommentableId}"); req.AddParameter(@"comment[message]", Message); - if (ReplyTo.HasValue) - req.AddParameter(@"comment[parent_id]", $"{ReplyTo}"); + if (ParentCommentId.HasValue) + req.AddParameter(@"comment[parent_id]", $"{ParentCommentId}"); return req; } From 3102044d00a85caaaafd059f77a08022dfd2d7aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 14 Jan 2023 18:46:14 +0100 Subject: [PATCH 081/376] Add failing test for new difficulty creation --- .../Editing/TestSceneEditorBeatmapCreation.cs | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs index a40c7814e1..3f89bf9e9c 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs @@ -20,6 +20,8 @@ using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.UI; +using osu.Game.Rulesets.Taiko; +using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Setup; using osu.Game.Storyboards; @@ -395,5 +397,52 @@ namespace osu.Game.Tests.Visual.Editing return set != null && set.PerformRead(s => s.Beatmaps.Count == 2 && s.Files.Count == 2); }); } + + [Test] + public void TestCreateNewDifficultyForInconvertibleRuleset() + { + Guid setId = Guid.Empty; + + AddStep("retrieve set ID", () => setId = EditorBeatmap.BeatmapInfo.BeatmapSet!.ID); + AddStep("save beatmap", () => Editor.Save()); + AddStep("try to create new taiko difficulty", () => Editor.CreateNewDifficulty(new TaikoRuleset().RulesetInfo)); + + AddUntilStep("wait for created", () => + { + string? difficultyName = Editor.ChildrenOfType().SingleOrDefault()?.BeatmapInfo.DifficultyName; + return difficultyName != null && difficultyName == "New Difficulty"; + }); + AddAssert("new difficulty persisted", () => + { + var set = beatmapManager.QueryBeatmapSet(s => s.ID == setId); + return set != null && set.PerformRead(s => s.Beatmaps.Count == 2 && s.Files.Count == 2); + }); + + AddStep("add timing point", () => EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 1000 })); + AddStep("add hitobjects", () => EditorBeatmap.AddRange(new[] + { + new Hit + { + StartTime = 0 + }, + new Hit + { + StartTime = 1000 + } + })); + AddStep("save beatmap", () => Editor.Save()); + AddStep("try to create new catch difficulty", () => Editor.CreateNewDifficulty(new CatchRuleset().RulesetInfo)); + + AddUntilStep("wait for created", () => + { + string? difficultyName = Editor.ChildrenOfType().SingleOrDefault()?.BeatmapInfo.DifficultyName; + return difficultyName != null && difficultyName == "New Difficulty (1)"; + }); + AddAssert("new difficulty persisted", () => + { + var set = beatmapManager.QueryBeatmapSet(s => s.ID == setId); + return set != null && set.PerformRead(s => s.Beatmaps.Count == 3 && s.Files.Count == 3); + }); + } } } From 88c3eef8e1b48e01827c50d10cacfca55bebad53 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 20:59:13 +0300 Subject: [PATCH 082/376] Add test case with no existing comments --- .../Online/TestSceneCommentsContainer.cs | 45 ++++++++++++++----- .../Overlays/Comments/CommentsContainer.cs | 2 +- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index e58423241b..4a41eca898 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -32,13 +32,18 @@ namespace osu.Game.Tests.Visual.Online private CommentsContainer commentsContainer; + private TextBox editorTextBox; + [SetUp] public void SetUp() => Schedule(() => + { Child = new BasicScrollContainer { RelativeSizeAxes = Axes.Both, Child = commentsContainer = new CommentsContainer() - }); + }; + editorTextBox = commentsContainer.ChildrenOfType().First(); + }); [Test] public void TestIdleState() @@ -129,21 +134,41 @@ namespace osu.Game.Tests.Visual.Online commentsContainer.ChildrenOfType().Count(d => d.Comment.Pinned == withPinned) == 1); } - [TestCase] + [Test] public void TestPost() + { + setUpCommentsResponse(new CommentBundle { Comments = new List() }); + AddStep("show comments", () => commentsContainer.ShowComments(CommentableType.Beatmapset, 123)); + AddAssert("no comments placeholder shown", () => commentsContainer.ChildrenOfType().Any()); + + setUpPostResponse(); + AddStep("enter text", () => editorTextBox.Current.Value = "comm"); + AddStep("submit", () => commentsContainer.ChildrenOfType().First().TriggerClick()); + + AddUntilStep("comment sent", () => + { + string writtenText = editorTextBox.Current.Value; + var comment = commentsContainer.ChildrenOfType().Last(); + return comment.ChildrenOfType().Any(y => y.Text == writtenText); + }); + AddAssert("no comments placeholder removed", () => !commentsContainer.ChildrenOfType().Any()); + } + + [Test] + public void TestPostWithExistingComments() { setUpCommentsResponse(getExampleComments()); AddStep("show comments", () => commentsContainer.ShowComments(CommentableType.Beatmapset, 123)); + setUpPostResponse(); - AddStep("Enter text", () => this.ChildrenOfType().Single().ChildrenOfType().Single().Current.Value = "comm"); - AddStep("Submit", () => this.ChildrenOfType().Single().ChildrenOfType().First().TriggerClick()); - AddUntilStep("Comment sent", () => + AddStep("enter text", () => editorTextBox.Current.Value = "comm"); + AddStep("submit", () => commentsContainer.ChildrenOfType().Single().ChildrenOfType().First().TriggerClick()); + + AddUntilStep("comment sent", () => { - string text = this.ChildrenOfType().Single().ChildrenOfType().Single().Current.Value; - return this.ChildrenOfType().Any(x => - { - return x.ChildrenOfType().Any(y => y.Text == text); - }); + string writtenText = editorTextBox.Current.Value; + var comment = commentsContainer.ChildrenOfType().Last(); + return comment.ChildrenOfType().Any(y => y.Text == writtenText); }); } diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 9446857f5e..a8939ffdc6 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -390,7 +390,7 @@ namespace osu.Game.Overlays.Comments base.Dispose(isDisposing); } - private partial class NoCommentsPlaceholder : CompositeDrawable + internal partial class NoCommentsPlaceholder : CompositeDrawable { [BackgroundDependencyLoader] private void load() From e7ab54379933937e8affbb008b0e3dacd3e3c92a Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Fri, 13 Jan 2023 16:08:34 -0800 Subject: [PATCH 083/376] Add ability to view converted beatmaps on beatmap set overlay --- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 4 ++++ osu.Game/Online/API/Requests/Responses/APIBeatmap.cs | 3 +++ osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs | 3 +++ osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 5 +++-- osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs | 3 ++- 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index 1665ec52fa..41db2399ac 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -13,6 +13,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; using osuTK; using osuTK.Graphics; @@ -116,6 +117,9 @@ namespace osu.Game.Beatmaps.Drawables private Drawable getRulesetIcon() { + if ((beatmap as APIBeatmap)?.Convert == true) + return rulesets.GetRuleset(0)!.CreateInstance().CreateIcon(); + int? onlineID = ruleset.OnlineID; if (onlineID >= 0 && rulesets.GetRuleset(onlineID.Value)?.CreateInstance() is Ruleset rulesetInstance) diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs index 27ad2a746c..7d6740ee46 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs @@ -63,6 +63,9 @@ namespace osu.Game.Online.API.Requests.Responses set => Length = TimeSpan.FromSeconds(value).TotalMilliseconds; } + [JsonProperty(@"convert")] + public bool Convert { get; set; } + [JsonProperty(@"count_circles")] public int CircleCount { get; set; } diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs index aeae3edde2..d39ed1e1ed 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs @@ -125,6 +125,9 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"beatmaps")] public APIBeatmap[] Beatmaps { get; set; } = Array.Empty(); + [JsonProperty(@"converts")] + public APIBeatmap[] Converts { get; set; } = Array.Empty(); + private BeatmapMetadata metadata => new BeatmapMetadata { Title = Title, diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index 84d12f2611..51b6b14579 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -168,9 +168,10 @@ namespace osu.Game.Overlays.BeatmapSet if (BeatmapSet != null) { - Difficulties.ChildrenEnumerable = BeatmapSet.Beatmaps + Difficulties.ChildrenEnumerable = BeatmapSet.Beatmaps.Concat(BeatmapSet.Converts) .Where(b => b.Ruleset.MatchesOnlineID(ruleset.Value)) - .OrderBy(b => b.StarRating) + .OrderBy(b => !b.Convert) + .ThenBy(b => b.StarRating) .Select(b => new DifficultySelectorButton(b) { State = DifficultySelectorState.NotSelected, diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs index f802807c3c..76e2f256b0 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs @@ -68,11 +68,12 @@ namespace osu.Game.Overlays.BeatmapSet BeatmapSet.BindValueChanged(setInfo => { int beatmapsCount = setInfo.NewValue?.Beatmaps.Count(b => b.Ruleset.MatchesOnlineID(Value)) ?? 0; + int osuBeatmaps = setInfo.NewValue?.Beatmaps.Count(b => b.Ruleset.OnlineID == 0) ?? 0; count.Text = beatmapsCount.ToString(); countContainer.FadeTo(beatmapsCount > 0 ? 1 : 0); - Enabled.Value = beatmapsCount > 0; + Enabled.Value = beatmapsCount > 0 || osuBeatmaps > 0; }, true); } } From a9facc076f37fc6663bae5e0b64c5e124bf9e3b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 14 Jan 2023 19:39:30 +0100 Subject: [PATCH 084/376] Fix difficulty creation flow failing for some ruleset combinations In current `master`, the difficulty creation flow would retrieve a "reference beatmap" to copy metadata and timing points from using `GetPlayableBeatmap()`. But, importantly, it was calling that method using *the ruleset of the new difficulty* rather than the ruleset of the existing one. This would make the difficulty creation flow fail if the beatmap couldn't be converted between rulesets (like taiko to catch). Fixing to use the reference beatmap's actual ruleset would be trivial, but there's no real reason to do all of that work anyway when a `WorkingBeatmap` is available. Because getting a playable beatmap is not required to copy across metadata and timing points, remove the `GetPlayableBeatmap()` step entirely to fix the bug. Closes #22145. --- osu.Game/Beatmaps/BeatmapManager.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index eafd1e96e8..34637501fa 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -136,14 +136,12 @@ namespace osu.Game.Beatmaps /// The ruleset with which the new difficulty should be created. public virtual WorkingBeatmap CreateNewDifficulty(BeatmapSetInfo targetBeatmapSet, WorkingBeatmap referenceWorkingBeatmap, RulesetInfo rulesetInfo) { - var playableBeatmap = referenceWorkingBeatmap.GetPlayableBeatmap(rulesetInfo); - - var newBeatmapInfo = new BeatmapInfo(rulesetInfo, new BeatmapDifficulty(), playableBeatmap.Metadata.DeepClone()) + var newBeatmapInfo = new BeatmapInfo(rulesetInfo, new BeatmapDifficulty(), referenceWorkingBeatmap.Metadata.DeepClone()) { DifficultyName = NamingUtils.GetNextBestName(targetBeatmapSet.Beatmaps.Select(b => b.DifficultyName), "New Difficulty") }; var newBeatmap = new Beatmap { BeatmapInfo = newBeatmapInfo }; - foreach (var timingPoint in playableBeatmap.ControlPointInfo.TimingPoints) + foreach (var timingPoint in referenceWorkingBeatmap.Beatmap.ControlPointInfo.TimingPoints) newBeatmap.ControlPointInfo.Add(timingPoint.Time, timingPoint.DeepClone()); return addDifficultyToSet(targetBeatmapSet, newBeatmap, referenceWorkingBeatmap.Skin); From cdf3aafdddd4c987c2ad8b5aa4ece2a03703f174 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 22:37:05 +0300 Subject: [PATCH 085/376] Add check for any drawables in content before looking for placeholder --- osu.Game/Overlays/Comments/CommentsContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index a8939ffdc6..58f7a72ee5 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -342,7 +342,7 @@ namespace osu.Game.Overlays.Comments { LoadComponentsAsync(topLevelComments, loaded => { - if (content[0] is NoCommentsPlaceholder placeholder) + if (content.Count > 0 && content[0] is NoCommentsPlaceholder placeholder) content.Remove(placeholder, true); foreach (var comment in loaded) From c2bb0949f52404739cea5dd5d544b3068615efb8 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 22:57:23 +0300 Subject: [PATCH 086/376] Take type and id from container directly on submit --- .../Overlays/Comments/CommentsContainer.cs | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 58f7a72ee5..67db0714dc 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -29,13 +29,10 @@ namespace osu.Game.Overlays.Comments [Cached] public partial class CommentsContainer : CompositeDrawable { - private const string cid = "commentableId"; - - [Cached] private readonly Bindable type = new Bindable(); - - [Cached(name: cid)] private readonly BindableLong id = new BindableLong(); + public IBindable Type => type; + public IBindable Id => id; public readonly Bindable Sort = new Bindable(); public readonly BindableBool ShowDeleted = new BindableBool(); @@ -413,24 +410,23 @@ namespace osu.Game.Overlays.Comments private partial class NewCommentEditor : CommentEditor { [Resolved] - public Bindable CommentableType { get; set; } - - [Resolved(name: cid)] - public BindableLong CommentableId { get; set; } - - protected override LocalisableString FooterText => default; - protected override LocalisableString CommitButtonText => CommonStrings.ButtonsPost; - protected override LocalisableString TextBoxPlaceholder => CommentsStrings.PlaceholderNew; + private CommentsContainer commentsContainer { get; set; } [Resolved] private IAPIProvider api { get; set; } public Action OnPost; + protected override LocalisableString FooterText => default; + + protected override LocalisableString CommitButtonText => CommonStrings.ButtonsPost; + + protected override LocalisableString TextBoxPlaceholder => CommentsStrings.PlaceholderNew; + protected override void OnCommit(string text) { ShowLoadingSpinner = true; - CommentPostRequest req = new CommentPostRequest(CommentableType.Value, CommentableId.Value, text); + CommentPostRequest req = new CommentPostRequest(commentsContainer.Type.Value, commentsContainer.Id.Value, text); req.Failure += _ => Schedule(() => { ShowLoadingSpinner = false; From c36922dd2c630dfb621633e359de61b0636941e7 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 22:57:51 +0300 Subject: [PATCH 087/376] Use clock to obtain a position for comment insertion --- osu.Game/Overlays/Comments/CommentsContainer.cs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 67db0714dc..c626d1f26c 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -344,15 +344,7 @@ namespace osu.Game.Overlays.Comments foreach (var comment in loaded) { - int pos = -1; - - if (content.Count > 0) - { - var first = content.FlowingChildren.First(); - pos = (int)(content.GetLayoutPosition(first) - 1); - } - - content.Insert(pos, comment); + content.Insert((int)-Clock.CurrentTime, comment); } }, (loadCancellation = new CancellationTokenSource()).Token); } From 58406cae19851cf6910ffb5fbc04aea54af78e42 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 23:42:10 +0300 Subject: [PATCH 088/376] Make test wait for comment loading --- .../Visual/Online/TestSceneCommentsContainer.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index 4a41eca898..3d8781d902 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.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; @@ -30,9 +28,9 @@ namespace osu.Game.Tests.Visual.Online private DummyAPIAccess dummyAPI => (DummyAPIAccess)API; - private CommentsContainer commentsContainer; + private CommentsContainer commentsContainer = null!; - private TextBox editorTextBox; + private TextBox editorTextBox = null!; [SetUp] public void SetUp() => Schedule(() => @@ -148,8 +146,8 @@ namespace osu.Game.Tests.Visual.Online AddUntilStep("comment sent", () => { string writtenText = editorTextBox.Current.Value; - var comment = commentsContainer.ChildrenOfType().Last(); - return comment.ChildrenOfType().Any(y => y.Text == writtenText); + var comment = commentsContainer.ChildrenOfType().LastOrDefault(); + return comment != null && comment.ChildrenOfType().Any(y => y.Text == writtenText); }); AddAssert("no comments placeholder removed", () => !commentsContainer.ChildrenOfType().Any()); } @@ -167,8 +165,8 @@ namespace osu.Game.Tests.Visual.Online AddUntilStep("comment sent", () => { string writtenText = editorTextBox.Current.Value; - var comment = commentsContainer.ChildrenOfType().Last(); - return comment.ChildrenOfType().Any(y => y.Text == writtenText); + var comment = commentsContainer.ChildrenOfType().LastOrDefault(); + return comment != null && comment.ChildrenOfType().Any(y => y.Text == writtenText); }); } From 1480c691ae8bbf2ca0fbe4b88acc5eb426f7ffc5 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 23:42:56 +0300 Subject: [PATCH 089/376] Explain empty string in editor's footer --- osu.Game/Overlays/Comments/CommentsContainer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index c626d1f26c..3639fe1835 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -409,6 +409,7 @@ namespace osu.Game.Overlays.Comments public Action OnPost; + //TODO should match web, left empty due to no multiline support protected override LocalisableString FooterText => default; protected override LocalisableString CommitButtonText => CommonStrings.ButtonsPost; From a68d4fe5d18da32ede6420f50520769e20739106 Mon Sep 17 00:00:00 2001 From: integer <7279624+integerrr@users.noreply.github.com> Date: Sat, 14 Jan 2023 21:18:51 +0000 Subject: [PATCH 090/376] make expansion to not use scheduler --- .../PlayerSettings/PlayerSettingsGroup.cs | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs index f4769cd417..55cf69b0f2 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs @@ -4,7 +4,6 @@ #nullable disable using osu.Framework.Input.Events; -using osu.Framework.Threading; using osu.Game.Overlays; namespace osu.Game.Screens.Play.PlayerSettings @@ -16,11 +15,16 @@ namespace osu.Game.Screens.Play.PlayerSettings { } - private ScheduledDelegate hoverExpandEvent; + private bool expandedByDefault = true; protected override bool OnHover(HoverEvent e) { - updateHoverExpansion(); + if (IsHovered && !Expanded.Value) + { + Expanded.Value = true; + expandedByDefault = false; + } + base.OnHover(e); // Importantly, return true to correctly take focus away from PlayerLoader. @@ -29,23 +33,10 @@ namespace osu.Game.Screens.Play.PlayerSettings protected override void OnHoverLost(HoverLostEvent e) { - if (hoverExpandEvent != null) - { - hoverExpandEvent?.Cancel(); - hoverExpandEvent = null; - + if (!expandedByDefault) Expanded.Value = false; - } base.OnHoverLost(e); } - - private void updateHoverExpansion() - { - hoverExpandEvent?.Cancel(); - - if (IsHovered && !Expanded.Value) - hoverExpandEvent = Scheduler.AddDelayed(() => Expanded.Value = true, 0); - } } } From 76eefc7573a5267ddf3016517d77e0eea1adf272 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sun, 15 Jan 2023 01:46:11 +0300 Subject: [PATCH 091/376] Add support for localisation where it was missing --- osu.Game/Graphics/UserInterface/OsuMenuItem.cs | 6 ++---- osu.Game/Graphics/UserInterface/StatefulMenuItem.cs | 11 +++++------ osu.Game/Graphics/UserInterface/ToggleMenuItem.cs | 7 +++---- .../Screens/Edit/Components/Menus/EditorMenuItem.cs | 9 +++++---- .../Components/Menus/EditorScreenSwitcherControl.cs | 5 ----- 5 files changed, 15 insertions(+), 23 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuMenuItem.cs b/osu.Game/Graphics/UserInterface/OsuMenuItem.cs index 9d65d6b8b9..20461de08f 100644 --- a/osu.Game/Graphics/UserInterface/OsuMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/OsuMenuItem.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; @@ -13,12 +11,12 @@ namespace osu.Game.Graphics.UserInterface { public readonly MenuItemType Type; - public OsuMenuItem(string text, MenuItemType type = MenuItemType.Standard) + public OsuMenuItem(LocalisableString text, MenuItemType type = MenuItemType.Standard) : this(text, type, null) { } - public OsuMenuItem(LocalisableString text, MenuItemType type, Action action) + public OsuMenuItem(LocalisableString text, MenuItemType type, Action? action) : base(text, action) { Type = type; diff --git a/osu.Game/Graphics/UserInterface/StatefulMenuItem.cs b/osu.Game/Graphics/UserInterface/StatefulMenuItem.cs index 17266e876c..85efd75a60 100644 --- a/osu.Game/Graphics/UserInterface/StatefulMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/StatefulMenuItem.cs @@ -1,11 +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 - using System; using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; namespace osu.Game.Graphics.UserInterface { @@ -25,7 +24,7 @@ namespace osu.Game.Graphics.UserInterface /// The text to display. /// A function that mutates a state to another state after this is pressed. /// The type of action which this performs. - protected StatefulMenuItem(string text, Func changeStateFunc, MenuItemType type = MenuItemType.Standard) + protected StatefulMenuItem(LocalisableString text, Func changeStateFunc, MenuItemType type = MenuItemType.Standard) : this(text, changeStateFunc, type, null) { } @@ -37,7 +36,7 @@ namespace osu.Game.Graphics.UserInterface /// A function that mutates a state to another state after this is pressed. /// The type of action which this performs. /// A delegate to be invoked when this is pressed. - protected StatefulMenuItem(string text, Func changeStateFunc, MenuItemType type, Action action) + protected StatefulMenuItem(LocalisableString text, Func? changeStateFunc, MenuItemType type, Action? action) : base(text, type) { Action.Value = () => @@ -69,7 +68,7 @@ namespace osu.Game.Graphics.UserInterface /// The text to display. /// A function that mutates a state to another state after this is pressed. /// The type of action which this performs. - protected StatefulMenuItem(string text, Func changeStateFunc, MenuItemType type = MenuItemType.Standard) + protected StatefulMenuItem(LocalisableString text, Func? changeStateFunc, MenuItemType type = MenuItemType.Standard) : this(text, changeStateFunc, type, null) { } @@ -81,7 +80,7 @@ namespace osu.Game.Graphics.UserInterface /// A function that mutates a state to another state after this is pressed. /// The type of action which this performs. /// A delegate to be invoked when this is pressed. - protected StatefulMenuItem(string text, Func changeStateFunc, MenuItemType type, Action action) + protected StatefulMenuItem(LocalisableString text, Func? changeStateFunc, MenuItemType type, Action? action) : base(text, o => changeStateFunc?.Invoke((T)o) ?? o, type, o => action?.Invoke((T)o)) { base.State.BindValueChanged(state => diff --git a/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs b/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs index 6787e17113..51e1248bc1 100644 --- a/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/ToggleMenuItem.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 osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; namespace osu.Game.Graphics.UserInterface { @@ -18,7 +17,7 @@ namespace osu.Game.Graphics.UserInterface /// /// The text to display. /// The type of action which this performs. - public ToggleMenuItem(string text, MenuItemType type = MenuItemType.Standard) + public ToggleMenuItem(LocalisableString text, MenuItemType type = MenuItemType.Standard) : this(text, type, null) { } @@ -29,7 +28,7 @@ namespace osu.Game.Graphics.UserInterface /// The text to display. /// The type of action which this performs. /// A delegate to be invoked when this is pressed. - public ToggleMenuItem(string text, MenuItemType type, Action action) + public ToggleMenuItem(LocalisableString text, MenuItemType type, Action? action) : base(text, value => !value, type, action) { } diff --git a/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs b/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs index 0a2c073dcd..1bd8979347 100644 --- a/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs +++ b/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using osu.Framework.Localisation; using osu.Game.Graphics.UserInterface; namespace osu.Game.Screens.Edit.Components.Menus @@ -10,13 +11,13 @@ namespace osu.Game.Screens.Edit.Components.Menus { private const int min_text_length = 40; - public EditorMenuItem(string text, MenuItemType type = MenuItemType.Standard) - : base(text.PadRight(min_text_length), type) + public EditorMenuItem(LocalisableString text, MenuItemType type = MenuItemType.Standard) + : base(LocalisableString.Interpolate($"{text,-min_text_length}"), type) { } - public EditorMenuItem(string text, MenuItemType type, Action action) - : base(text.PadRight(min_text_length), type, action) + public EditorMenuItem(LocalisableString text, MenuItemType type, Action action) + : base(LocalisableString.Interpolate($"{text,-min_text_length}"), type, action) { } } diff --git a/osu.Game/Screens/Edit/Components/Menus/EditorScreenSwitcherControl.cs b/osu.Game/Screens/Edit/Components/Menus/EditorScreenSwitcherControl.cs index 3d51874082..1f6d61d0ad 100644 --- a/osu.Game/Screens/Edit/Components/Menus/EditorScreenSwitcherControl.cs +++ b/osu.Game/Screens/Edit/Components/Menus/EditorScreenSwitcherControl.cs @@ -56,11 +56,6 @@ namespace osu.Game.Screens.Edit.Components.Menus Bar.Expire(); } - [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) - { - } - protected override void OnActivated() { base.OnActivated(); From 24df23f42038d890ad645bc7430351baf3314afc Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sun, 15 Jan 2023 01:49:19 +0300 Subject: [PATCH 092/376] Localise background header --- osu.Game/Localisation/EditorSetupStrings.cs | 26 ++++++++++++++----- .../Edit/Setup/SetupScreenHeaderBackground.cs | 3 ++- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/osu.Game/Localisation/EditorSetupStrings.cs b/osu.Game/Localisation/EditorSetupStrings.cs index 0431b9cf76..4ddacf2c5b 100644 --- a/osu.Game/Localisation/EditorSetupStrings.cs +++ b/osu.Game/Localisation/EditorSetupStrings.cs @@ -42,7 +42,8 @@ namespace osu.Game.Localisation /// /// "If enabled, an "Are you ready? 3, 2, 1, GO!" countdown will be inserted at the beginning of the beatmap, assuming there is enough time to do so." /// - public static LocalisableString CountdownDescription => new TranslatableString(getKey(@"countdown_description"), @"If enabled, an ""Are you ready? 3, 2, 1, GO!"" countdown will be inserted at the beginning of the beatmap, assuming there is enough time to do so."); + public static LocalisableString CountdownDescription => new TranslatableString(getKey(@"countdown_description"), + @"If enabled, an ""Are you ready? 3, 2, 1, GO!"" countdown will be inserted at the beginning of the beatmap, assuming there is enough time to do so."); /// /// "Countdown speed" @@ -52,7 +53,8 @@ namespace osu.Game.Localisation /// /// "If the countdown sounds off-time, use this to make it appear one or more beats early." /// - public static LocalisableString CountdownOffsetDescription => new TranslatableString(getKey(@"countdown_offset_description"), @"If the countdown sounds off-time, use this to make it appear one or more beats early."); + public static LocalisableString CountdownOffsetDescription => + new TranslatableString(getKey(@"countdown_offset_description"), @"If the countdown sounds off-time, use this to make it appear one or more beats early."); /// /// "Countdown offset" @@ -67,7 +69,8 @@ namespace osu.Game.Localisation /// /// "Allows storyboards to use the full screen space, rather than be confined to a 4:3 area." /// - public static LocalisableString WidescreenSupportDescription => new TranslatableString(getKey(@"widescreen_support_description"), @"Allows storyboards to use the full screen space, rather than be confined to a 4:3 area."); + public static LocalisableString WidescreenSupportDescription => + new TranslatableString(getKey(@"widescreen_support_description"), @"Allows storyboards to use the full screen space, rather than be confined to a 4:3 area."); /// /// "Epilepsy warning" @@ -77,7 +80,8 @@ namespace osu.Game.Localisation /// /// "Recommended if the storyboard or video contain scenes with rapidly flashing colours." /// - public static LocalisableString EpilepsyWarningDescription => new TranslatableString(getKey(@"epilepsy_warning_description"), @"Recommended if the storyboard or video contain scenes with rapidly flashing colours."); + public static LocalisableString EpilepsyWarningDescription => + new TranslatableString(getKey(@"epilepsy_warning_description"), @"Recommended if the storyboard or video contain scenes with rapidly flashing colours."); /// /// "Letterbox during breaks" @@ -87,7 +91,8 @@ namespace osu.Game.Localisation /// /// "Adds horizontal letterboxing to give a cinematic look during breaks." /// - public static LocalisableString LetterboxDuringBreaksDescription => new TranslatableString(getKey(@"letterbox_during_breaks_description"), @"Adds horizontal letterboxing to give a cinematic look during breaks."); + public static LocalisableString LetterboxDuringBreaksDescription => + new TranslatableString(getKey(@"letterbox_during_breaks_description"), @"Adds horizontal letterboxing to give a cinematic look during breaks."); /// /// "Samples match playback rate" @@ -97,7 +102,8 @@ namespace osu.Game.Localisation /// /// "When enabled, all samples will speed up or slow down when rate-changing mods are enabled." /// - public static LocalisableString SamplesMatchPlaybackRateDescription => new TranslatableString(getKey(@"samples_match_playback_rate_description"), @"When enabled, all samples will speed up or slow down when rate-changing mods are enabled."); + public static LocalisableString SamplesMatchPlaybackRateDescription => new TranslatableString(getKey(@"samples_match_playback_rate_description"), + @"When enabled, all samples will speed up or slow down when rate-changing mods are enabled."); /// /// "The size of all hit objects" @@ -117,7 +123,8 @@ namespace osu.Game.Localisation /// /// "The harshness of hit windows and difficulty of special objects (ie. spinners)" /// - public static LocalisableString OverallDifficultyDescription => new TranslatableString(getKey(@"overall_difficulty_description"), @"The harshness of hit windows and difficulty of special objects (ie. spinners)"); + public static LocalisableString OverallDifficultyDescription => + new TranslatableString(getKey(@"overall_difficulty_description"), @"The harshness of hit windows and difficulty of special objects (ie. spinners)"); /// /// "Metadata" @@ -199,6 +206,11 @@ namespace osu.Game.Localisation /// public static LocalisableString DifficultyHeader => new TranslatableString(getKey(@"difficulty_header"), @"Difficulty"); + /// + /// "Drag image here to set beatmap background!" + /// + public static LocalisableString DragToSetBackground => new TranslatableString(getKey(@"drag_to_set_background"), @"Drag image here to set beatmap background!"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Screens/Edit/Setup/SetupScreenHeaderBackground.cs b/osu.Game/Screens/Edit/Setup/SetupScreenHeaderBackground.cs index 47a7512adf..033e5361bb 100644 --- a/osu.Game/Screens/Edit/Setup/SetupScreenHeaderBackground.cs +++ b/osu.Game/Screens/Edit/Setup/SetupScreenHeaderBackground.cs @@ -10,6 +10,7 @@ using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Localisation; namespace osu.Game.Screens.Edit.Setup { @@ -61,7 +62,7 @@ namespace osu.Game.Screens.Edit.Setup }, new OsuTextFlowContainer(t => t.Font = OsuFont.Default.With(size: 24)) { - Text = "Drag image here to set beatmap background!", + Text = EditorSetupStrings.DragToSetBackground, Anchor = Anchor.Centre, Origin = Anchor.Centre, AutoSizeAxes = Axes.Both From 78e562903df18bf7c24d31bc640636b4fe029d78 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sun, 15 Jan 2023 01:50:41 +0300 Subject: [PATCH 093/376] Localise part of editor --- osu.Game/Localisation/EditorStrings.cs | 164 ++++++++++++++++++ .../Screens/Edit/BackgroundDimMenuItem.cs | 13 +- .../Edit/Components/PlaybackControl.cs | 3 +- .../Timelines/Summary/TestGameplayButton.cs | 3 +- .../Components/Timeline/TimelineArea.cs | 7 +- osu.Game/Screens/Edit/Editor.cs | 39 ++--- osu.Game/Screens/Edit/EditorScreenMode.cs | 15 +- .../Screens/Edit/WaveformOpacityMenuItem.cs | 3 +- 8 files changed, 207 insertions(+), 40 deletions(-) create mode 100644 osu.Game/Localisation/EditorStrings.cs diff --git a/osu.Game/Localisation/EditorStrings.cs b/osu.Game/Localisation/EditorStrings.cs new file mode 100644 index 0000000000..32078468c9 --- /dev/null +++ b/osu.Game/Localisation/EditorStrings.cs @@ -0,0 +1,164 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Localisation; + +namespace osu.Game.Localisation +{ + public static class EditorStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.Editor"; + + /// + /// "File" + /// + public static LocalisableString File => new TranslatableString(getKey(@"file"), @"File"); + + /// + /// "Edit" + /// + public static LocalisableString Edit => new TranslatableString(getKey(@"edit"), @"Edit"); + + /// + /// "Undo" + /// + public static LocalisableString Undo => new TranslatableString(getKey(@"undo"), @"Undo"); + + /// + /// "Redo" + /// + public static LocalisableString Redo => new TranslatableString(getKey(@"redo"), @"Redo"); + + /// + /// "Cut" + /// + public static LocalisableString Cut => new TranslatableString(getKey(@"cut"), @"Cut"); + + /// + /// "Copy" + /// + public static LocalisableString Copy => new TranslatableString(getKey(@"copy"), @"Copy"); + + /// + /// "Paste" + /// + public static LocalisableString Paste => new TranslatableString(getKey(@"paste"), @"Paste"); + + /// + /// "Clone" + /// + public static LocalisableString Clone => new TranslatableString(getKey(@"clone"), @"Clone"); + + /// + /// "View" + /// + public static LocalisableString View => new TranslatableString(getKey(@"view"), @"View"); + + /// + /// "Background dim" + /// + public static LocalisableString BackgroundDim => new TranslatableString(getKey(@"background_dim"), @"Background dim"); + + /// + /// "Waveform opacity" + /// + public static LocalisableString WaveformOpacity => new TranslatableString(getKey(@"waveform_opacity"), @"Waveform opacity"); + + /// + /// "Show hit markers" + /// + public static LocalisableString ShowHitMarkers => new TranslatableString(getKey(@"show_hit_markers"), @"Show hit markers"); + + /// + /// "Timing" + /// + public static LocalisableString Timing => new TranslatableString(getKey(@"timing"), @"Timing"); + + /// + /// "Set preview point to current time" + /// + public static LocalisableString SetPreviewPointToCurrent => new TranslatableString(getKey(@"set_preview_point_to_current"), @"Set preview point to current time"); + + /// + /// "Save" + /// + public static LocalisableString Save => new TranslatableString(getKey(@"save"), @"Save"); + + /// + /// "Export package" + /// + public static LocalisableString ExportPackage => new TranslatableString(getKey(@"export_package"), @"Export package"); + + /// + /// "Create new difficulty" + /// + public static LocalisableString CreateNewDifficulty => new TranslatableString(getKey(@"create_new_difficulty"), @"Create new difficulty"); + + /// + /// "Change difficulty" + /// + public static LocalisableString ChangeDifficulty => new TranslatableString(getKey(@"change_difficulty"), @"Change difficulty"); + + /// + /// "Delete difficulty" + /// + public static LocalisableString DeleteDifficulty => new TranslatableString(getKey(@"delete_difficulty"), @"Delete difficulty"); + + /// + /// "Exit" + /// + public static LocalisableString Exit => new TranslatableString(getKey(@"exit"), @"Exit"); + + /// + /// "setup" + /// + public static LocalisableString SetupScreen => new TranslatableString(getKey(@"setup_screen"), @"setup"); + + /// + /// "compose" + /// + public static LocalisableString ComposeScreen => new TranslatableString(getKey(@"compose_screen"), @"compose"); + + /// + /// "design" + /// + public static LocalisableString DesignScreen => new TranslatableString(getKey(@"design_screen"), @"design"); + + /// + /// "timing" + /// + public static LocalisableString TimingScreen => new TranslatableString(getKey(@"timing_screen"), @"timing"); + + /// + /// "verify" + /// + public static LocalisableString VerifyScreen => new TranslatableString(getKey(@"verify_screen"), @"verify"); + + /// + /// "Playback speed" + /// + public static LocalisableString PlaybackSpeed => new TranslatableString(getKey(@"playback_speed"), @"Playback speed"); + + /// + /// "Test!" + /// + public static LocalisableString TestBeatmap => new TranslatableString(getKey(@"test_beatmap"), @"Test!"); + + /// + /// "Waveform" + /// + public static LocalisableString TimelineWaveform => new TranslatableString(getKey(@"timeline_waveform"), @"Waveform"); + + /// + /// "Ticks" + /// + public static LocalisableString TimelineTicks => new TranslatableString(getKey(@"timeline_ticks"), @"Ticks"); + + /// + /// "BPM" + /// + public static LocalisableString TimelineBpm => new TranslatableString(getKey(@"timeline_bpm"), @"BPM"); + + private static string getKey(string key) => $@"{prefix}:{key}"; + } +} diff --git a/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs b/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs index b5a33f06e7..bff01385bb 100644 --- a/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs +++ b/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs @@ -5,17 +5,18 @@ using System.Collections.Generic; using osu.Framework.Bindables; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; namespace osu.Game.Screens.Edit { internal class BackgroundDimMenuItem : MenuItem { - private readonly Bindable backgroudDim; + private readonly Bindable backgroundDim; private readonly Dictionary menuItemLookup = new Dictionary(); - public BackgroundDimMenuItem(Bindable backgroudDim) - : base("Background dim") + public BackgroundDimMenuItem(Bindable backgroundDim) + : base(EditorStrings.BackgroundDim) { Items = new[] { @@ -25,8 +26,8 @@ namespace osu.Game.Screens.Edit createMenuItem(0.75f), }; - this.backgroudDim = backgroudDim; - backgroudDim.BindValueChanged(dim => + this.backgroundDim = backgroundDim; + backgroundDim.BindValueChanged(dim => { foreach (var kvp in menuItemLookup) kvp.Value.State.Value = kvp.Key == dim.NewValue ? TernaryState.True : TernaryState.False; @@ -40,6 +41,6 @@ namespace osu.Game.Screens.Edit return item; } - private void updateOpacity(float dim) => backgroudDim.Value = dim; + private void updateOpacity(float dim) => backgroundDim.Value = dim; } } diff --git a/osu.Game/Screens/Edit/Components/PlaybackControl.cs b/osu.Game/Screens/Edit/Components/PlaybackControl.cs index 87cbcb8aff..72c299f443 100644 --- a/osu.Game/Screens/Edit/Components/PlaybackControl.cs +++ b/osu.Game/Screens/Edit/Components/PlaybackControl.cs @@ -16,6 +16,7 @@ using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Overlays; using osuTK.Input; @@ -47,7 +48,7 @@ namespace osu.Game.Screens.Edit.Components new OsuSpriteText { Origin = Anchor.BottomLeft, - Text = "Playback speed", + Text = EditorStrings.PlaybackSpeed, RelativePositionAxes = Axes.Y, Y = 0.5f, Padding = new MarginPadding { Left = 45 } diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/TestGameplayButton.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/TestGameplayButton.cs index 9b45464e81..169e72fe3f 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/TestGameplayButton.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/TestGameplayButton.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Overlays; namespace osu.Game.Screens.Edit.Components.Timelines.Summary @@ -30,7 +31,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary Content.CornerRadius = 0; - Text = "Test!"; + Text = EditorStrings.TestBeatmap; } } } diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs index 615925ff91..f11c7b1d00 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Overlays; using osuTK; @@ -75,17 +76,17 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline { waveformCheckbox = new OsuCheckbox { - LabelText = "Waveform", + LabelText = EditorStrings.TimelineWaveform, Current = { Value = true }, }, ticksCheckbox = new OsuCheckbox { - LabelText = "Ticks", + LabelText = EditorStrings.TimelineTicks, Current = { Value = true }, }, controlPointsCheckbox = new OsuCheckbox { - LabelText = "BPM", + LabelText = EditorStrings.TimelineBpm, Current = { Value = true }, }, } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index be4e2f9628..c440cc8285 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -51,7 +51,6 @@ using osu.Game.Screens.Edit.Verify; using osu.Game.Screens.Play; using osu.Game.Users; using osuTK.Input; -using CommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; namespace osu.Game.Screens.Edit { @@ -294,40 +293,40 @@ namespace osu.Game.Screens.Edit RelativeSizeAxes = Axes.Both, Items = new[] { - new MenuItem("File") + new MenuItem(EditorStrings.File) { Items = createFileMenuItems() }, - new MenuItem(CommonStrings.ButtonsEdit) + new MenuItem(EditorStrings.Edit) { Items = new[] { - undoMenuItem = new EditorMenuItem("Undo", MenuItemType.Standard, Undo), - redoMenuItem = new EditorMenuItem("Redo", MenuItemType.Standard, Redo), + undoMenuItem = new EditorMenuItem(EditorStrings.Undo, MenuItemType.Standard, Undo), + redoMenuItem = new EditorMenuItem(EditorStrings.Redo, MenuItemType.Standard, Redo), new EditorMenuItemSpacer(), - cutMenuItem = new EditorMenuItem("Cut", MenuItemType.Standard, Cut), - copyMenuItem = new EditorMenuItem("Copy", MenuItemType.Standard, Copy), - pasteMenuItem = new EditorMenuItem("Paste", MenuItemType.Standard, Paste), - cloneMenuItem = new EditorMenuItem("Clone", MenuItemType.Standard, Clone), + cutMenuItem = new EditorMenuItem(EditorStrings.Cut, MenuItemType.Standard, Cut), + copyMenuItem = new EditorMenuItem(EditorStrings.Copy, MenuItemType.Standard, Copy), + pasteMenuItem = new EditorMenuItem(EditorStrings.Paste, MenuItemType.Standard, Paste), + cloneMenuItem = new EditorMenuItem(EditorStrings.Clone, MenuItemType.Standard, Clone), } }, - new MenuItem("View") + new MenuItem(EditorStrings.View) { Items = new MenuItem[] { new WaveformOpacityMenuItem(config.GetBindable(OsuSetting.EditorWaveformOpacity)), new BackgroundDimMenuItem(editorBackgroundDim), - new ToggleMenuItem("Show hit markers") + new ToggleMenuItem(EditorStrings.ShowHitMarkers) { State = { BindTarget = editorHitMarkers }, } } }, - new MenuItem("Timing") + new MenuItem(EditorStrings.Timing) { Items = new MenuItem[] { - new EditorMenuItem("Set preview point to current time", MenuItemType.Standard, SetPreviewPointToCurrentTime) + new EditorMenuItem(EditorStrings.SetPreviewPointToCurrent, MenuItemType.Standard, SetPreviewPointToCurrentTime) } } } @@ -716,7 +715,7 @@ namespace osu.Game.Screens.Edit if (!(refetchedBeatmap is DummyWorkingBeatmap)) { - Logger.Log("Editor providing re-fetched beatmap post edit session"); + Logger.Log(@"Editor providing re-fetched beatmap post edit session"); Beatmap.Value = refetchedBeatmap; } } @@ -952,15 +951,15 @@ namespace osu.Game.Screens.Edit private List createFileMenuItems() => new List { - new EditorMenuItem("Save", MenuItemType.Standard, () => Save()), - new EditorMenuItem("Export package", MenuItemType.Standard, exportBeatmap) { Action = { Disabled = !RuntimeInfo.IsDesktop } }, + new EditorMenuItem(EditorStrings.Save, MenuItemType.Standard, () => Save()), + new EditorMenuItem(EditorStrings.ExportPackage, MenuItemType.Standard, exportBeatmap) { Action = { Disabled = !RuntimeInfo.IsDesktop } }, new EditorMenuItemSpacer(), createDifficultyCreationMenu(), createDifficultySwitchMenu(), new EditorMenuItemSpacer(), - new EditorMenuItem("Delete difficulty", MenuItemType.Standard, deleteDifficulty) { Action = { Disabled = Beatmap.Value.BeatmapSetInfo.Beatmaps.Count < 2 } }, + new EditorMenuItem(EditorStrings.DeleteDifficulty, MenuItemType.Standard, deleteDifficulty) { Action = { Disabled = Beatmap.Value.BeatmapSetInfo.Beatmaps.Count < 2 } }, new EditorMenuItemSpacer(), - new EditorMenuItem("Exit", MenuItemType.Standard, this.Exit) + new EditorMenuItem(EditorStrings.Exit, MenuItemType.Standard, this.Exit) }; private void exportBeatmap() @@ -1009,7 +1008,7 @@ namespace osu.Game.Screens.Edit foreach (var ruleset in rulesets.AvailableRulesets) rulesetItems.Add(new EditorMenuItem(ruleset.Name, MenuItemType.Standard, () => CreateNewDifficulty(ruleset))); - return new EditorMenuItem("Create new difficulty") { Items = rulesetItems }; + return new EditorMenuItem(EditorStrings.CreateNewDifficulty) { Items = rulesetItems }; } protected void CreateNewDifficulty(RulesetInfo rulesetInfo) @@ -1045,7 +1044,7 @@ namespace osu.Game.Screens.Edit } } - return new EditorMenuItem("Change difficulty") { Items = difficultyItems }; + return new EditorMenuItem(EditorStrings.ChangeDifficulty) { Items = difficultyItems }; } protected void SwitchToDifficulty(BeatmapInfo nextBeatmap) => loader?.ScheduleSwitchToExistingDifficulty(nextBeatmap, GetState(nextBeatmap.Ruleset)); diff --git a/osu.Game/Screens/Edit/EditorScreenMode.cs b/osu.Game/Screens/Edit/EditorScreenMode.cs index 81fcf23cdf..f787fee1e0 100644 --- a/osu.Game/Screens/Edit/EditorScreenMode.cs +++ b/osu.Game/Screens/Edit/EditorScreenMode.cs @@ -1,27 +1,26 @@ // 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.ComponentModel; +using osu.Framework.Localisation; +using osu.Game.Localisation; namespace osu.Game.Screens.Edit { public enum EditorScreenMode { - [Description("setup")] + [LocalisableDescription(typeof(EditorStrings), nameof(EditorStrings.SetupScreen))] SongSetup, - [Description("compose")] + [LocalisableDescription(typeof(EditorStrings), nameof(EditorStrings.ComposeScreen))] Compose, - [Description("design")] + [LocalisableDescription(typeof(EditorStrings), nameof(EditorStrings.DesignScreen))] Design, - [Description("timing")] + [LocalisableDescription(typeof(EditorStrings), nameof(EditorStrings.TimingScreen))] Timing, - [Description("verify")] + [LocalisableDescription(typeof(EditorStrings), nameof(EditorStrings.VerifyScreen))] Verify, } } diff --git a/osu.Game/Screens/Edit/WaveformOpacityMenuItem.cs b/osu.Game/Screens/Edit/WaveformOpacityMenuItem.cs index 3d3f67e70e..5b1d7142e4 100644 --- a/osu.Game/Screens/Edit/WaveformOpacityMenuItem.cs +++ b/osu.Game/Screens/Edit/WaveformOpacityMenuItem.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using osu.Framework.Bindables; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; namespace osu.Game.Screens.Edit { @@ -17,7 +18,7 @@ namespace osu.Game.Screens.Edit private readonly Dictionary menuItemLookup = new Dictionary(); public WaveformOpacityMenuItem(Bindable waveformOpacity) - : base("Waveform opacity") + : base(EditorStrings.WaveformOpacity) { Items = new[] { From 87650044bbecc58bcdd74ee4920b3a21603a6f9d Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sun, 15 Jan 2023 01:49:54 +0300 Subject: [PATCH 094/376] Localise create/save dialog --- osu.Game/Localisation/EditorDialogsStrings.cs | 54 +++++++++++++++++++ .../Screens/Edit/CreateNewDifficultyDialog.cs | 11 ++-- osu.Game/Screens/Edit/PromptForSaveDialog.cs | 11 ++-- 3 files changed, 64 insertions(+), 12 deletions(-) create mode 100644 osu.Game/Localisation/EditorDialogsStrings.cs diff --git a/osu.Game/Localisation/EditorDialogsStrings.cs b/osu.Game/Localisation/EditorDialogsStrings.cs new file mode 100644 index 0000000000..fc4c2b7f2a --- /dev/null +++ b/osu.Game/Localisation/EditorDialogsStrings.cs @@ -0,0 +1,54 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Localisation; + +namespace osu.Game.Localisation +{ + public static class EditorDialogsStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.EditorDialogs"; + + /// + /// "Would you like to create a blank difficulty?" + /// + public static LocalisableString NewDifficultyDialogHeader => new TranslatableString(getKey(@"new_difficulty_dialog_header"), @"Would you like to create a blank difficulty?"); + + /// + /// "Yeah, let's start from scratch!" + /// + public static LocalisableString CreateNew => new TranslatableString(getKey(@"create_new"), @"Yeah, let's start from scratch!"); + + /// + /// "No, create an exact copy of this difficulty" + /// + public static LocalisableString CreateCopy => new TranslatableString(getKey(@"create_copy"), @"No, create an exact copy of this difficulty"); + + /// + /// "I changed my mind, I want to keep editing this difficulty" + /// + public static LocalisableString KeepEditing => new TranslatableString(getKey(@"keep_editing"), @"I changed my mind, I want to keep editing this difficulty"); + + /// + /// "Did you want to save your changes?" + /// + public static LocalisableString SaveDialogHeader => new TranslatableString(getKey(@"save_dialog_header"), @"Did you want to save your changes?"); + + /// + /// "Save my masterpiece!" + /// + public static LocalisableString Save => new TranslatableString(getKey(@"save"), @"Save my masterpiece!"); + + /// + /// "Forget all changes" + /// + public static LocalisableString ForgetAllChanges => new TranslatableString(getKey(@"forget_all_changes"), @"Forget all changes"); + + /// + /// "Oops, continue editing" + /// + public static LocalisableString ContinueEditing => new TranslatableString(getKey(@"continue_editing"), @"Oops, continue editing"); + + private static string getKey(string key) => $@"{prefix}:{key}"; + } +} diff --git a/osu.Game/Screens/Edit/CreateNewDifficultyDialog.cs b/osu.Game/Screens/Edit/CreateNewDifficultyDialog.cs index 85466c5056..811da5236e 100644 --- a/osu.Game/Screens/Edit/CreateNewDifficultyDialog.cs +++ b/osu.Game/Screens/Edit/CreateNewDifficultyDialog.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 osu.Framework.Graphics.Sprites; using osu.Game.Overlays.Dialog; +using osu.Game.Localisation; namespace osu.Game.Screens.Edit { @@ -20,7 +19,7 @@ namespace osu.Game.Screens.Edit public CreateNewDifficultyDialog(CreateNewDifficulty createNewDifficulty) { - HeaderText = "Would you like to create a blank difficulty?"; + HeaderText = EditorDialogsStrings.NewDifficultyDialogHeader; Icon = FontAwesome.Regular.Clone; @@ -28,17 +27,17 @@ namespace osu.Game.Screens.Edit { new PopupDialogOkButton { - Text = "Yeah, let's start from scratch!", + Text = EditorDialogsStrings.CreateNew, Action = () => createNewDifficulty.Invoke(false) }, new PopupDialogCancelButton { - Text = "No, create an exact copy of this difficulty", + Text = EditorDialogsStrings.CreateCopy, Action = () => createNewDifficulty.Invoke(true) }, new PopupDialogCancelButton { - Text = "I changed my mind, I want to keep editing this difficulty", + Text = EditorDialogsStrings.KeepEditing, Action = () => { } } }; diff --git a/osu.Game/Screens/Edit/PromptForSaveDialog.cs b/osu.Game/Screens/Edit/PromptForSaveDialog.cs index 2a2cd019ea..7d78465e6c 100644 --- a/osu.Game/Screens/Edit/PromptForSaveDialog.cs +++ b/osu.Game/Screens/Edit/PromptForSaveDialog.cs @@ -1,11 +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 - using System; using osu.Framework.Graphics.Sprites; using osu.Game.Overlays.Dialog; +using osu.Game.Localisation; namespace osu.Game.Screens.Edit { @@ -13,7 +12,7 @@ namespace osu.Game.Screens.Edit { public PromptForSaveDialog(Action exit, Action saveAndExit, Action cancel) { - HeaderText = "Did you want to save your changes?"; + HeaderText = EditorDialogsStrings.SaveDialogHeader; Icon = FontAwesome.Regular.Save; @@ -21,17 +20,17 @@ namespace osu.Game.Screens.Edit { new PopupDialogOkButton { - Text = @"Save my masterpiece!", + Text = EditorDialogsStrings.Save, Action = saveAndExit }, new PopupDialogDangerousButton { - Text = @"Forget all changes", + Text = EditorDialogsStrings.ForgetAllChanges, Action = exit }, new PopupDialogCancelButton { - Text = @"Oops, continue editing", + Text = EditorDialogsStrings.ContinueEditing, Action = cancel }, }; From 8777d5349bd9e816d9ceff9b0891bc51ca0014ea Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sun, 15 Jan 2023 14:39:34 +0300 Subject: [PATCH 095/376] Use existing strings --- osu.Game/Localisation/EditorStrings.cs | 15 --------------- osu.Game/Screens/Edit/BackgroundDimMenuItem.cs | 2 +- .../Compose/Components/Timeline/TimelineArea.cs | 3 ++- osu.Game/Screens/Edit/Editor.cs | 3 ++- 4 files changed, 5 insertions(+), 18 deletions(-) diff --git a/osu.Game/Localisation/EditorStrings.cs b/osu.Game/Localisation/EditorStrings.cs index 32078468c9..6b16e43bd3 100644 --- a/osu.Game/Localisation/EditorStrings.cs +++ b/osu.Game/Localisation/EditorStrings.cs @@ -54,11 +54,6 @@ namespace osu.Game.Localisation /// public static LocalisableString View => new TranslatableString(getKey(@"view"), @"View"); - /// - /// "Background dim" - /// - public static LocalisableString BackgroundDim => new TranslatableString(getKey(@"background_dim"), @"Background dim"); - /// /// "Waveform opacity" /// @@ -79,11 +74,6 @@ namespace osu.Game.Localisation /// public static LocalisableString SetPreviewPointToCurrent => new TranslatableString(getKey(@"set_preview_point_to_current"), @"Set preview point to current time"); - /// - /// "Save" - /// - public static LocalisableString Save => new TranslatableString(getKey(@"save"), @"Save"); - /// /// "Export package" /// @@ -154,11 +144,6 @@ namespace osu.Game.Localisation /// public static LocalisableString TimelineTicks => new TranslatableString(getKey(@"timeline_ticks"), @"Ticks"); - /// - /// "BPM" - /// - public static LocalisableString TimelineBpm => new TranslatableString(getKey(@"timeline_bpm"), @"BPM"); - private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs b/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs index bff01385bb..2a1159eb27 100644 --- a/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs +++ b/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs @@ -16,7 +16,7 @@ namespace osu.Game.Screens.Edit private readonly Dictionary menuItemLookup = new Dictionary(); public BackgroundDimMenuItem(Bindable backgroundDim) - : base(EditorStrings.BackgroundDim) + : base(GameplaySettingsStrings.BackgroundDim) { Items = new[] { diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs index f11c7b1d00..0b83258f8b 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; using osu.Game.Overlays; +using osu.Game.Resources.Localisation.Web; using osuTK; namespace osu.Game.Screens.Edit.Compose.Components.Timeline @@ -86,7 +87,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline }, controlPointsCheckbox = new OsuCheckbox { - LabelText = EditorStrings.TimelineBpm, + LabelText = BeatmapsetsStrings.ShowStatsBpm, Current = { Value = true }, }, } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index c440cc8285..29be1a3881 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -51,6 +51,7 @@ using osu.Game.Screens.Edit.Verify; using osu.Game.Screens.Play; using osu.Game.Users; using osuTK.Input; +using CommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; namespace osu.Game.Screens.Edit { @@ -951,7 +952,7 @@ namespace osu.Game.Screens.Edit private List createFileMenuItems() => new List { - new EditorMenuItem(EditorStrings.Save, MenuItemType.Standard, () => Save()), + new EditorMenuItem(CommonStrings.ButtonsSave, MenuItemType.Standard, () => Save()), new EditorMenuItem(EditorStrings.ExportPackage, MenuItemType.Standard, exportBeatmap) { Action = { Disabled = !RuntimeInfo.IsDesktop } }, new EditorMenuItemSpacer(), createDifficultyCreationMenu(), From 5d2e09137cfed291d842458972c4c8c2e64073be Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sun, 15 Jan 2023 14:40:53 +0300 Subject: [PATCH 096/376] Remove text padding in editor menu for now --- osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs b/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs index 1bd8979347..368fe40977 100644 --- a/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs +++ b/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs @@ -9,15 +9,13 @@ namespace osu.Game.Screens.Edit.Components.Menus { public class EditorMenuItem : OsuMenuItem { - private const int min_text_length = 40; - public EditorMenuItem(LocalisableString text, MenuItemType type = MenuItemType.Standard) - : base(LocalisableString.Interpolate($"{text,-min_text_length}"), type) + : base(text, type) { } public EditorMenuItem(LocalisableString text, MenuItemType type, Action action) - : base(LocalisableString.Interpolate($"{text,-min_text_length}"), type, action) + : base(text, type, action) { } } From f7af5a8115d5566a623a9ba8d3b6a5679bc13d29 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 15 Jan 2023 22:35:44 +0900 Subject: [PATCH 097/376] Revert some formatting changes --- osu.Game/Screens/Select/SongSelect.cs | 54 +++++++++++++-------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index ef5827fad7..0e108d3db0 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -314,17 +314,16 @@ namespace osu.Game.Screens.Select /// Creates the buttons to be displayed in the footer. /// /// A set of and an optional which the button opens when pressed. - protected virtual IEnumerable<(FooterButton, OverlayContainer?)> CreateFooterButtons() => - new (FooterButton, OverlayContainer?)[] + protected virtual IEnumerable<(FooterButton, OverlayContainer?)> CreateFooterButtons() => new (FooterButton, OverlayContainer?)[] + { + (new FooterButtonMods { Current = Mods }, ModSelect), + (new FooterButtonRandom { - (new FooterButtonMods { Current = Mods }, ModSelect), - (new FooterButtonRandom - { - NextRandom = () => Carousel.SelectNextRandom(), - PreviousRandom = Carousel.SelectPreviousRandom - }, null), - (beatmapOptionsButton = new FooterButtonOptions(), BeatmapOptions) - }; + NextRandom = () => Carousel.SelectNextRandom(), + PreviousRandom = Carousel.SelectPreviousRandom + }, null), + (beatmapOptionsButton = new FooterButtonOptions(), BeatmapOptions) + }; protected virtual ModSelectOverlay CreateModSelectOverlay() => new SoloModSelectOverlay(); @@ -425,25 +424,26 @@ namespace osu.Game.Screens.Select Logger.Log($"Song select working beatmap updated to {beatmap}"); - if (Carousel.SelectBeatmap(beatmap.BeatmapInfo, false)) return; - - // A selection may not have been possible with filters applied. - - // There was possibly a ruleset mismatch. This is a case we can help things along by updating the game-wide ruleset to match. - if (!beatmap.BeatmapInfo.Ruleset.Equals(decoupledRuleset.Value)) + if (!Carousel.SelectBeatmap(beatmap.BeatmapInfo, false)) { - Ruleset.Value = beatmap.BeatmapInfo.Ruleset; - transferRulesetValue(); + // A selection may not have been possible with filters applied. + + // There was possibly a ruleset mismatch. This is a case we can help things along by updating the game-wide ruleset to match. + if (!beatmap.BeatmapInfo.Ruleset.Equals(decoupledRuleset.Value)) + { + Ruleset.Value = beatmap.BeatmapInfo.Ruleset; + transferRulesetValue(); + } + + // Even if a ruleset mismatch was not the cause (ie. a text filter is applied), + // we still want to temporarily show the new beatmap, bypassing filters. + // This will be undone the next time the user changes the filter. + var criteria = FilterControl.CreateCriteria(); + criteria.SelectedBeatmapSet = beatmap.BeatmapInfo.BeatmapSet; + Carousel.Filter(criteria); + + Carousel.SelectBeatmap(beatmap.BeatmapInfo); } - - // Even if a ruleset mismatch was not the cause (ie. a text filter is applied), - // we still want to temporarily show the new beatmap, bypassing filters. - // This will be undone the next time the user changes the filter. - var criteria = FilterControl.CreateCriteria(); - criteria.SelectedBeatmapSet = beatmap.BeatmapInfo.BeatmapSet; - Carousel.Filter(criteria); - - Carousel.SelectBeatmap(beatmap.BeatmapInfo); } // We need to keep track of the last selected beatmap ignoring debounce to play the correct selection sounds. From 4cf4a6685802831dee21b6d0cc0047c453ec608b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 15 Jan 2023 22:43:30 +0900 Subject: [PATCH 098/376] Make `MusicController` a required dependency of `SongSelect` --- osu.Game/Screens/Select/SongSelect.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 0e108d3db0..d7c1dbf543 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -34,6 +34,7 @@ using osu.Framework.Input.Bindings; using osu.Game.Collections; using osu.Game.Graphics.UserInterface; using System.Diagnostics; +using osu.Framework.Extensions.ObjectExtensions; using osu.Game.Screens.Play; using osu.Game.Skinning; @@ -118,7 +119,7 @@ namespace osu.Game.Screens.Select private IDisposable? modSelectOverlayRegistration; [Resolved] - private MusicController? music { get; set; } + private MusicController music { get; set; } = null!; [Resolved] internal IOverlayManager? OverlayManager { get; private set; } @@ -616,7 +617,6 @@ namespace osu.Game.Screens.Select { // restart playback on returning to song select, regardless. // not sure this should be a permanent thing (we may want to leave a user pause paused even on returning) - Debug.Assert(music != null); music.ResetTrackAdjustments(); music.Play(requestedByUser: true); } @@ -692,7 +692,6 @@ namespace osu.Game.Screens.Select ensureTrackLooping(Beatmap.Value, TrackChangeDirection.None); - Debug.Assert(music != null); music.TrackChanged += ensureTrackLooping; } @@ -702,7 +701,6 @@ namespace osu.Game.Screens.Select if (!isHandlingLooping) return; - Debug.Assert(music != null); music.CurrentTrack.Looping = isHandlingLooping = false; music.TrackChanged -= ensureTrackLooping; @@ -728,7 +726,7 @@ namespace osu.Game.Screens.Select decoupledRuleset.UnbindAll(); - if (music != null) + if (music.IsNotNull()) music.TrackChanged -= ensureTrackLooping; modSelectOverlayRegistration?.Dispose(); @@ -774,7 +772,6 @@ namespace osu.Game.Screens.Select if (!ControlGlobalMusic) return; - Debug.Assert(music != null); ITrack track = music.CurrentTrack; bool isNewTrack = !lastTrack.TryGetTarget(out var last) || last != track; From 9a29c9ae26a94f35d1a3cc4aff6678ab388847e7 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Sun, 15 Jan 2023 15:32:53 +0100 Subject: [PATCH 099/376] remove hacky method to check if carousel is null --- 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 d7c1dbf543..d4d75d0ad6 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -128,7 +128,7 @@ namespace osu.Game.Screens.Select private void load(AudioManager audio, OsuColour colours, ManageCollectionsDialog? manageCollectionsDialog, DifficultyRecommender? recommender) { // initial value transfer is required for FilterControl (it uses our re-cached bindables in its async load for the initial filter). - transferRulesetValue(false); + transferRulesetValue(); LoadComponentAsync(Carousel = new BeatmapCarousel { @@ -852,7 +852,7 @@ namespace osu.Game.Screens.Select /// Will immediately run filter operations if required. /// /// Whether a transfer occurred. - private bool transferRulesetValue(bool carouselLoaded = true) + private bool transferRulesetValue() { if (decoupledRuleset.Value?.Equals(Ruleset.Value) == true) return false; @@ -860,8 +860,8 @@ namespace osu.Game.Screens.Select Logger.Log($"decoupled ruleset transferred (\"{decoupledRuleset.Value}\" -> \"{Ruleset.Value}\")"); rulesetNoDebounce = decoupledRuleset.Value = Ruleset.Value; - // We don't want to declare the carousel as nullable, so this check allows us to avoid running the carousel flush during the loading process - if (!carouselLoaded) return true; + // We want to check for null since this method gets called before the loading of the carousel. + if (Carousel.IsNull()) return true; // if we have a pending filter operation, we want to run it now. // it could change selection (ie. if the ruleset has been changed). From 00acea59fca4254630d4a21555be1ab8ffc9fccb Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sun, 15 Jan 2023 19:37:40 +0300 Subject: [PATCH 100/376] Move some strings to common --- osu.Game/Localisation/CommonStrings.cs | 50 ++++++++++++++++++++++++++ osu.Game/Localisation/EditorStrings.cs | 50 -------------------------- osu.Game/Screens/Edit/Editor.cs | 25 +++++++------ 3 files changed, 62 insertions(+), 63 deletions(-) diff --git a/osu.Game/Localisation/CommonStrings.cs b/osu.Game/Localisation/CommonStrings.cs index 385ebd0593..10178915a2 100644 --- a/osu.Game/Localisation/CommonStrings.cs +++ b/osu.Game/Localisation/CommonStrings.cs @@ -104,6 +104,56 @@ namespace osu.Game.Localisation /// public static LocalisableString Description => new TranslatableString(getKey(@"description"), @"Description"); + /// + /// "File" + /// + public static LocalisableString MenuBarFile => new TranslatableString(getKey(@"menu_bar_file"), @"File"); + + /// + /// "Edit" + /// + public static LocalisableString MenuBarEdit => new TranslatableString(getKey(@"menu_bar_edit"), @"Edit"); + + /// + /// "View" + /// + public static LocalisableString MenuBarView => new TranslatableString(getKey(@"menu_bar_view"), @"View"); + + /// + /// "Undo" + /// + public static LocalisableString Undo => new TranslatableString(getKey(@"undo"), @"Undo"); + + /// + /// "Redo" + /// + public static LocalisableString Redo => new TranslatableString(getKey(@"redo"), @"Redo"); + + /// + /// "Cut" + /// + public static LocalisableString Cut => new TranslatableString(getKey(@"cut"), @"Cut"); + + /// + /// "Copy" + /// + public static LocalisableString Copy => new TranslatableString(getKey(@"copy"), @"Copy"); + + /// + /// "Paste" + /// + public static LocalisableString Paste => new TranslatableString(getKey(@"paste"), @"Paste"); + + /// + /// "Clone" + /// + public static LocalisableString Clone => new TranslatableString(getKey(@"clone"), @"Clone"); + + /// + /// "Exit" + /// + public static LocalisableString Exit => new TranslatableString(getKey(@"exit"), @"Exit"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Localisation/EditorStrings.cs b/osu.Game/Localisation/EditorStrings.cs index 6b16e43bd3..96c08aa6f8 100644 --- a/osu.Game/Localisation/EditorStrings.cs +++ b/osu.Game/Localisation/EditorStrings.cs @@ -9,51 +9,6 @@ namespace osu.Game.Localisation { private const string prefix = @"osu.Game.Resources.Localisation.Editor"; - /// - /// "File" - /// - public static LocalisableString File => new TranslatableString(getKey(@"file"), @"File"); - - /// - /// "Edit" - /// - public static LocalisableString Edit => new TranslatableString(getKey(@"edit"), @"Edit"); - - /// - /// "Undo" - /// - public static LocalisableString Undo => new TranslatableString(getKey(@"undo"), @"Undo"); - - /// - /// "Redo" - /// - public static LocalisableString Redo => new TranslatableString(getKey(@"redo"), @"Redo"); - - /// - /// "Cut" - /// - public static LocalisableString Cut => new TranslatableString(getKey(@"cut"), @"Cut"); - - /// - /// "Copy" - /// - public static LocalisableString Copy => new TranslatableString(getKey(@"copy"), @"Copy"); - - /// - /// "Paste" - /// - public static LocalisableString Paste => new TranslatableString(getKey(@"paste"), @"Paste"); - - /// - /// "Clone" - /// - public static LocalisableString Clone => new TranslatableString(getKey(@"clone"), @"Clone"); - - /// - /// "View" - /// - public static LocalisableString View => new TranslatableString(getKey(@"view"), @"View"); - /// /// "Waveform opacity" /// @@ -94,11 +49,6 @@ namespace osu.Game.Localisation /// public static LocalisableString DeleteDifficulty => new TranslatableString(getKey(@"delete_difficulty"), @"Delete difficulty"); - /// - /// "Exit" - /// - public static LocalisableString Exit => new TranslatableString(getKey(@"exit"), @"Exit"); - /// /// "setup" /// diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 29be1a3881..74ea933255 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -51,7 +51,7 @@ using osu.Game.Screens.Edit.Verify; using osu.Game.Screens.Play; using osu.Game.Users; using osuTK.Input; -using CommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; +using WebCommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; namespace osu.Game.Screens.Edit { @@ -294,24 +294,24 @@ namespace osu.Game.Screens.Edit RelativeSizeAxes = Axes.Both, Items = new[] { - new MenuItem(EditorStrings.File) + new MenuItem(CommonStrings.MenuBarFile) { Items = createFileMenuItems() }, - new MenuItem(EditorStrings.Edit) + new MenuItem(CommonStrings.MenuBarEdit) { Items = new[] { - undoMenuItem = new EditorMenuItem(EditorStrings.Undo, MenuItemType.Standard, Undo), - redoMenuItem = new EditorMenuItem(EditorStrings.Redo, MenuItemType.Standard, Redo), + undoMenuItem = new EditorMenuItem(CommonStrings.Undo, MenuItemType.Standard, Undo), + redoMenuItem = new EditorMenuItem(CommonStrings.Redo, MenuItemType.Standard, Redo), new EditorMenuItemSpacer(), - cutMenuItem = new EditorMenuItem(EditorStrings.Cut, MenuItemType.Standard, Cut), - copyMenuItem = new EditorMenuItem(EditorStrings.Copy, MenuItemType.Standard, Copy), - pasteMenuItem = new EditorMenuItem(EditorStrings.Paste, MenuItemType.Standard, Paste), - cloneMenuItem = new EditorMenuItem(EditorStrings.Clone, MenuItemType.Standard, Clone), + cutMenuItem = new EditorMenuItem(CommonStrings.Cut, MenuItemType.Standard, Cut), + copyMenuItem = new EditorMenuItem(CommonStrings.Copy, MenuItemType.Standard, Copy), + pasteMenuItem = new EditorMenuItem(CommonStrings.Paste, MenuItemType.Standard, Paste), + cloneMenuItem = new EditorMenuItem(CommonStrings.Clone, MenuItemType.Standard, Clone), } }, - new MenuItem(EditorStrings.View) + new MenuItem(CommonStrings.MenuBarView) { Items = new MenuItem[] { @@ -344,7 +344,6 @@ namespace osu.Game.Screens.Edit bottomBar = new BottomBar(), } }); - changeHandler?.CanUndo.BindValueChanged(v => undoMenuItem.Action.Disabled = !v.NewValue, true); changeHandler?.CanRedo.BindValueChanged(v => redoMenuItem.Action.Disabled = !v.NewValue, true); @@ -952,7 +951,7 @@ namespace osu.Game.Screens.Edit private List createFileMenuItems() => new List { - new EditorMenuItem(CommonStrings.ButtonsSave, MenuItemType.Standard, () => Save()), + new EditorMenuItem(WebCommonStrings.ButtonsSave, MenuItemType.Standard, () => Save()), new EditorMenuItem(EditorStrings.ExportPackage, MenuItemType.Standard, exportBeatmap) { Action = { Disabled = !RuntimeInfo.IsDesktop } }, new EditorMenuItemSpacer(), createDifficultyCreationMenu(), @@ -960,7 +959,7 @@ namespace osu.Game.Screens.Edit new EditorMenuItemSpacer(), new EditorMenuItem(EditorStrings.DeleteDifficulty, MenuItemType.Standard, deleteDifficulty) { Action = { Disabled = Beatmap.Value.BeatmapSetInfo.Beatmaps.Count < 2 } }, new EditorMenuItemSpacer(), - new EditorMenuItem(EditorStrings.Exit, MenuItemType.Standard, this.Exit) + new EditorMenuItem(CommonStrings.Exit, MenuItemType.Standard, this.Exit) }; private void exportBeatmap() From 9ce7c51b149401e3988eafbbe8461de7a86f1993 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sun, 15 Jan 2023 23:29:58 +0300 Subject: [PATCH 101/376] Localise osu! settings --- .../UI/OsuSettingsSubsection.cs | 11 +++++----- .../Localisation/RulesetSettingsStrings.cs | 20 +++++++++++++++++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/OsuSettingsSubsection.cs b/osu.Game.Rulesets.Osu/UI/OsuSettingsSubsection.cs index f711a0fc31..64c4e7eef6 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuSettingsSubsection.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuSettingsSubsection.cs @@ -1,11 +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 - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Localisation; +using osu.Game.Localisation; using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Osu.Configuration; using osu.Game.Rulesets.UI; @@ -30,23 +29,23 @@ namespace osu.Game.Rulesets.Osu.UI { new SettingsCheckbox { - LabelText = "Snaking in sliders", + LabelText = RulesetSettingsStrings.SnakingInSliders, Current = config.GetBindable(OsuRulesetSetting.SnakingInSliders) }, new SettingsCheckbox { ClassicDefault = false, - LabelText = "Snaking out sliders", + LabelText = RulesetSettingsStrings.SnakingOutSliders, Current = config.GetBindable(OsuRulesetSetting.SnakingOutSliders) }, new SettingsCheckbox { - LabelText = "Cursor trail", + LabelText = RulesetSettingsStrings.CursorTrail, Current = config.GetBindable(OsuRulesetSetting.ShowCursorTrail) }, new SettingsEnumDropdown { - LabelText = "Playfield border style", + LabelText = RulesetSettingsStrings.PlayfieldBorderStyle, Current = config.GetBindable(OsuRulesetSetting.PlayfieldBorderStyle), }, }; diff --git a/osu.Game/Localisation/RulesetSettingsStrings.cs b/osu.Game/Localisation/RulesetSettingsStrings.cs index bc4be56c80..dd2b7b0040 100644 --- a/osu.Game/Localisation/RulesetSettingsStrings.cs +++ b/osu.Game/Localisation/RulesetSettingsStrings.cs @@ -14,6 +14,26 @@ namespace osu.Game.Localisation /// public static LocalisableString Rulesets => new TranslatableString(getKey(@"rulesets"), @"Rulesets"); + /// + /// "Snaking in sliders" + /// + public static LocalisableString SnakingInSliders => new TranslatableString(getKey(@"snaking_in_sliders"), @"Snaking in sliders"); + + /// + /// "Snaking out sliders" + /// + public static LocalisableString SnakingOutSliders => new TranslatableString(getKey(@"snaking_out_sliders"), @"Snaking out sliders"); + + /// + /// "Cursor trail" + /// + public static LocalisableString CursorTrail => new TranslatableString(getKey(@"cursor_trail"), @"Cursor trail"); + + /// + /// "Playfield border style" + /// + public static LocalisableString PlayfieldBorderStyle => new TranslatableString(getKey(@"playfield_border_style"), @"Playfield border style"); + /// /// "None" /// From 6f84641596871a0f64c2a82e702c21f2e32aef8e Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sun, 15 Jan 2023 23:30:11 +0300 Subject: [PATCH 102/376] Localise osu!mania settings --- .../ManiaSettingsSubsection.cs | 9 +++--- .../UI/ManiaScrollingDirection.cs | 7 +++-- .../Localisation/RulesetSettingsStrings.cs | 30 +++++++++++++++++++ 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs b/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs index 9ed555da51..f5a5771386 100644 --- a/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs +++ b/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Mania.Configuration; using osu.Game.Rulesets.Mania.UI; @@ -30,18 +31,18 @@ namespace osu.Game.Rulesets.Mania { new SettingsEnumDropdown { - LabelText = "Scrolling direction", + LabelText = RulesetSettingsStrings.ScrollingDirection, Current = config.GetBindable(ManiaRulesetSetting.ScrollDirection) }, new SettingsSlider { - LabelText = "Scroll speed", + LabelText = RulesetSettingsStrings.ScrollSpeed, Current = config.GetBindable(ManiaRulesetSetting.ScrollTime), KeyboardStep = 5 }, new SettingsCheckbox { - LabelText = "Timing-based note colouring", + LabelText = RulesetSettingsStrings.TimingBasedColouring, Current = config.GetBindable(ManiaRulesetSetting.TimingBasedNoteColouring), } }; @@ -49,7 +50,7 @@ namespace osu.Game.Rulesets.Mania private partial class ManiaScrollSlider : OsuSliderBar { - public override LocalisableString TooltipText => $"{Current.Value}ms (speed {(int)Math.Round(DrawableManiaRuleset.MAX_TIME_RANGE / Current.Value)})"; + public override LocalisableString TooltipText => RulesetSettingsStrings.ScrollSpeedTooltip(Current.Value, (int)Math.Round(DrawableManiaRuleset.MAX_TIME_RANGE / Current.Value)); } } } diff --git a/osu.Game.Rulesets.Mania/UI/ManiaScrollingDirection.cs b/osu.Game.Rulesets.Mania/UI/ManiaScrollingDirection.cs index 44fe4b1b30..d36e6057bb 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaScrollingDirection.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaScrollingDirection.cs @@ -1,15 +1,18 @@ // 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.Localisation; +using osu.Game.Localisation; using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.Mania.UI { public enum ManiaScrollingDirection { + [LocalisableDescription(typeof(RulesetSettingsStrings), nameof(RulesetSettingsStrings.Up))] Up = ScrollingDirection.Up, + + [LocalisableDescription(typeof(RulesetSettingsStrings), nameof(RulesetSettingsStrings.Down))] Down = ScrollingDirection.Down } } diff --git a/osu.Game/Localisation/RulesetSettingsStrings.cs b/osu.Game/Localisation/RulesetSettingsStrings.cs index dd2b7b0040..0374f81cee 100644 --- a/osu.Game/Localisation/RulesetSettingsStrings.cs +++ b/osu.Game/Localisation/RulesetSettingsStrings.cs @@ -49,6 +49,36 @@ namespace osu.Game.Localisation /// public static LocalisableString BorderFull => new TranslatableString(getKey(@"full_borders"), @"Full"); + /// + /// "Scrolling direction" + /// + public static LocalisableString ScrollingDirection => new TranslatableString(getKey(@"scrolling_direction"), @"Scrolling direction"); + + /// + /// "Up" + /// + public static LocalisableString Up => new TranslatableString(getKey(@"scrolling_up"), @"Up"); + + /// + /// "Down" + /// + public static LocalisableString Down => new TranslatableString(getKey(@"scrolling_down"), @"Down"); + + /// + /// "Scroll speed" + /// + public static LocalisableString ScrollSpeed => new TranslatableString(getKey(@"scroll_speed"), @"Scroll speed"); + + /// + /// "Timing-based note colouring" + /// + public static LocalisableString TimingBasedColouring => new TranslatableString(getKey(@"Timing_based_colouring"), @"Timing-based note colouring"); + + /// + /// "{0}ms (speed {1})" + /// + public static LocalisableString ScrollSpeedTooltip(double arg0, int arg1) => new TranslatableString(getKey(@"ruleset"), @"{0}ms (speed {1})", arg0, arg1); + private static string getKey(string key) => $@"{prefix}:{key}"; } } From 85c1932851bf71202805c9cbcfe133d32ee3088b Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 15 Jan 2023 12:46:41 -0800 Subject: [PATCH 103/376] Mark `Converts` as nullable --- osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs | 2 +- osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs index d39ed1e1ed..d98715a42d 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs @@ -126,7 +126,7 @@ namespace osu.Game.Online.API.Requests.Responses public APIBeatmap[] Beatmaps { get; set; } = Array.Empty(); [JsonProperty(@"converts")] - public APIBeatmap[] Converts { get; set; } = Array.Empty(); + public APIBeatmap[]? Converts { get; set; } private BeatmapMetadata metadata => new BeatmapMetadata { diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index 51b6b14579..0ee7dfc9bd 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -168,7 +168,7 @@ namespace osu.Game.Overlays.BeatmapSet if (BeatmapSet != null) { - Difficulties.ChildrenEnumerable = BeatmapSet.Beatmaps.Concat(BeatmapSet.Converts) + Difficulties.ChildrenEnumerable = BeatmapSet.Beatmaps.Concat(BeatmapSet.Converts ?? Array.Empty()) .Where(b => b.Ruleset.MatchesOnlineID(ruleset.Value)) .OrderBy(b => !b.Convert) .ThenBy(b => b.StarRating) From b733f46c6fed49d930da4e0cf20d5949c5914ddd Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 15 Jan 2023 14:15:36 -0800 Subject: [PATCH 104/376] Apply NRT to `BeatmapPicker` --- .../TestSceneStartupBeatmapDisplay.cs | 4 +--- osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 22 +++++++++---------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneStartupBeatmapDisplay.cs b/osu.Game.Tests/Visual/Navigation/TestSceneStartupBeatmapDisplay.cs index 0c165bc40e..25cef8440a 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneStartupBeatmapDisplay.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneStartupBeatmapDisplay.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.Linq; using NUnit.Framework; using osu.Framework.Graphics.Containers; @@ -50,7 +48,7 @@ namespace osu.Game.Tests.Visual.Navigation public void TestBeatmapLink() { AddUntilStep("Beatmap overlay displayed", () => Game.ChildrenOfType().FirstOrDefault()?.State.Value == Visibility.Visible); - AddUntilStep("Beatmap overlay showing content", () => Game.ChildrenOfType().FirstOrDefault()?.Beatmap.Value.OnlineID == requested_beatmap_id); + AddUntilStep("Beatmap overlay showing content", () => Game.ChildrenOfType().FirstOrDefault()?.Beatmap.Value?.OnlineID == requested_beatmap_id); } } } diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index 0ee7dfc9bd..76fc1bbf53 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Linq; using osu.Framework; @@ -38,10 +36,10 @@ namespace osu.Game.Overlays.BeatmapSet public readonly DifficultiesContainer Difficulties; - public readonly Bindable Beatmap = new Bindable(); - private APIBeatmapSet beatmapSet; + public readonly Bindable Beatmap = new Bindable(); + private APIBeatmapSet? beatmapSet; - public APIBeatmapSet BeatmapSet + public APIBeatmapSet? BeatmapSet { get => beatmapSet; set @@ -142,7 +140,7 @@ namespace osu.Game.Overlays.BeatmapSet } [Resolved] - private IBindable ruleset { get; set; } + private IBindable ruleset { get; set; } = null!; [BackgroundDependencyLoader] private void load(OsuColour colours) @@ -200,9 +198,9 @@ namespace osu.Game.Overlays.BeatmapSet updateDifficultyButtons(); } - private void showBeatmap(IBeatmapInfo beatmapInfo) + private void showBeatmap(IBeatmapInfo? beatmapInfo) { - version.Text = beatmapInfo?.DifficultyName; + version.Text = beatmapInfo?.DifficultyName ?? string.Empty; } private void updateDifficultyButtons() @@ -212,7 +210,7 @@ namespace osu.Game.Overlays.BeatmapSet public partial class DifficultiesContainer : FillFlowContainer { - public Action OnLostHover; + public Action? OnLostHover; protected override void OnHoverLost(HoverLostEvent e) { @@ -233,9 +231,9 @@ namespace osu.Game.Overlays.BeatmapSet public readonly APIBeatmap Beatmap; - public Action OnHovered; - public Action OnClicked; - public event Action StateChanged; + public Action? OnHovered; + public Action? OnClicked; + public event Action? StateChanged; private DifficultySelectorState state; From ae49e724e43ebe449f1229c1efbed7157d00ba23 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 15 Jan 2023 14:17:46 -0800 Subject: [PATCH 105/376] Move converted beatmap icons logic locally --- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 4 ---- osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index 41db2399ac..1665ec52fa 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -13,7 +13,6 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; using osu.Game.Graphics.Containers; -using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; using osuTK; using osuTK.Graphics; @@ -117,9 +116,6 @@ namespace osu.Game.Beatmaps.Drawables private Drawable getRulesetIcon() { - if ((beatmap as APIBeatmap)?.Convert == true) - return rulesets.GetRuleset(0)!.CreateInstance().CreateIcon(); - int? onlineID = ruleset.OnlineID; if (onlineID >= 0 && rulesets.GetRuleset(onlineID.Value)?.CreateInstance() is Ruleset rulesetInstance) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index 76fc1bbf53..585e0dd1a2 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -170,7 +170,7 @@ namespace osu.Game.Overlays.BeatmapSet .Where(b => b.Ruleset.MatchesOnlineID(ruleset.Value)) .OrderBy(b => !b.Convert) .ThenBy(b => b.StarRating) - .Select(b => new DifficultySelectorButton(b) + .Select(b => new DifficultySelectorButton(b, b.Convert ? new RulesetInfo { OnlineID = 0 } : null) { State = DifficultySelectorState.NotSelected, OnHovered = beatmap => @@ -254,7 +254,7 @@ namespace osu.Game.Overlays.BeatmapSet } } - public DifficultySelectorButton(APIBeatmap beatmapInfo) + public DifficultySelectorButton(APIBeatmap beatmapInfo, IRulesetInfo? ruleset) { Beatmap = beatmapInfo; Size = new Vector2(size); @@ -273,7 +273,7 @@ namespace osu.Game.Overlays.BeatmapSet Alpha = 0.5f } }, - icon = new DifficultyIcon(beatmapInfo) + icon = new DifficultyIcon(beatmapInfo, ruleset) { ShowTooltip = false, Current = { Value = new StarDifficulty(beatmapInfo.StarRating, 0) }, From 0ff143d4c86d7e6ae19f703201046cab5592c01a Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 15 Jan 2023 15:19:06 -0800 Subject: [PATCH 106/376] Add argument for play some ruleset string --- osu.Game/Localisation/ToolbarStrings.cs | 5 ++--- osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Localisation/ToolbarStrings.cs b/osu.Game/Localisation/ToolbarStrings.cs index b76c643332..02a68a6bdc 100644 --- a/osu.Game/Localisation/ToolbarStrings.cs +++ b/osu.Game/Localisation/ToolbarStrings.cs @@ -30,10 +30,9 @@ namespace osu.Game.Localisation public static LocalisableString HomeHeaderDescription => new TranslatableString(getKey(@"header_description"), @"return to the main menu"); /// - /// "play some" + /// "play some {0}" /// - - public static LocalisableString RulesetHeaderDescription => new TranslatableString(getKey(@"header_description"), @"play some"); + public static LocalisableString PlaySomeRuleset(string arg0) => new TranslatableString(getKey(@"play_some_ruleset"), @"play some {0}", arg0); private static string getKey(string key) => $@"{prefix}:{key}"; } diff --git a/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs b/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs index d603863888..07f7d52545 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs @@ -7,7 +7,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; -using osu.Framework.Localisation; using osu.Game.Localisation; using osu.Game.Rulesets; using osuTK.Graphics; @@ -31,7 +30,7 @@ namespace osu.Game.Overlays.Toolbar var rInstance = value.CreateInstance(); ruleset.TooltipMain = rInstance.Description; - ruleset.TooltipSub = LocalisableString.Format("{0} {1}", ToolbarStrings.RulesetHeaderDescription, ($"{rInstance.Description}")); + ruleset.TooltipSub = ToolbarStrings.PlaySomeRuleset(rInstance.Description); ruleset.SetIcon(rInstance.CreateIcon()); } From 6a847faea9ad82990e7aa2ab94eb10eb2767112b Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 15 Jan 2023 15:19:47 -0800 Subject: [PATCH 107/376] Make home string keys more specific --- osu.Game/Localisation/ToolbarStrings.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Localisation/ToolbarStrings.cs b/osu.Game/Localisation/ToolbarStrings.cs index 02a68a6bdc..e71a3fff9b 100644 --- a/osu.Game/Localisation/ToolbarStrings.cs +++ b/osu.Game/Localisation/ToolbarStrings.cs @@ -22,12 +22,12 @@ namespace osu.Game.Localisation /// /// "home" /// - public static LocalisableString HomeHeaderTitle => new TranslatableString(getKey(@"header_title"), @"home"); + public static LocalisableString HomeHeaderTitle => new TranslatableString(getKey(@"home_header_title"), @"home"); /// /// "return to the main menu" /// - public static LocalisableString HomeHeaderDescription => new TranslatableString(getKey(@"header_description"), @"return to the main menu"); + public static LocalisableString HomeHeaderDescription => new TranslatableString(getKey(@"home_header_description"), @"return to the main menu"); /// /// "play some {0}" From d19b35bd5fc225434a7f7288392b2c409ec2db8c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Jan 2023 13:18:49 +0900 Subject: [PATCH 108/376] Rename ambiguous translation keys --- osu.Game.Rulesets.Mania/UI/ManiaScrollingDirection.cs | 4 ++-- osu.Game/Localisation/RulesetSettingsStrings.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Mania/UI/ManiaScrollingDirection.cs b/osu.Game.Rulesets.Mania/UI/ManiaScrollingDirection.cs index d36e6057bb..4a8843c999 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaScrollingDirection.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaScrollingDirection.cs @@ -9,10 +9,10 @@ namespace osu.Game.Rulesets.Mania.UI { public enum ManiaScrollingDirection { - [LocalisableDescription(typeof(RulesetSettingsStrings), nameof(RulesetSettingsStrings.Up))] + [LocalisableDescription(typeof(RulesetSettingsStrings), nameof(RulesetSettingsStrings.ScrollingDirectionUp))] Up = ScrollingDirection.Up, - [LocalisableDescription(typeof(RulesetSettingsStrings), nameof(RulesetSettingsStrings.Down))] + [LocalisableDescription(typeof(RulesetSettingsStrings), nameof(RulesetSettingsStrings.ScrollingDirectionDown))] Down = ScrollingDirection.Down } } diff --git a/osu.Game/Localisation/RulesetSettingsStrings.cs b/osu.Game/Localisation/RulesetSettingsStrings.cs index 0374f81cee..1b0df6ecf6 100644 --- a/osu.Game/Localisation/RulesetSettingsStrings.cs +++ b/osu.Game/Localisation/RulesetSettingsStrings.cs @@ -57,12 +57,12 @@ namespace osu.Game.Localisation /// /// "Up" /// - public static LocalisableString Up => new TranslatableString(getKey(@"scrolling_up"), @"Up"); + public static LocalisableString ScrollingDirectionUp => new TranslatableString(getKey(@"scrolling_up"), @"Up"); /// /// "Down" /// - public static LocalisableString Down => new TranslatableString(getKey(@"scrolling_down"), @"Down"); + public static LocalisableString ScrollingDirectionDown => new TranslatableString(getKey(@"scrolling_down"), @"Down"); /// /// "Scroll speed" From eb0f30c6414b84f73b22d56aaae543546cd2e111 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Jan 2023 13:28:45 +0900 Subject: [PATCH 109/376] Use scroll speed localisation in one more usage --- .../Configuration/ManiaRulesetConfigManager.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Configuration/ManiaRulesetConfigManager.cs b/osu.Game.Rulesets.Mania/Configuration/ManiaRulesetConfigManager.cs index d367c82ed8..99a80ef28d 100644 --- a/osu.Game.Rulesets.Mania/Configuration/ManiaRulesetConfigManager.cs +++ b/osu.Game.Rulesets.Mania/Configuration/ManiaRulesetConfigManager.cs @@ -4,6 +4,7 @@ using System; using osu.Framework.Configuration.Tracking; using osu.Game.Configuration; +using osu.Game.Localisation; using osu.Game.Rulesets.Configuration; using osu.Game.Rulesets.Mania.UI; @@ -30,8 +31,8 @@ namespace osu.Game.Rulesets.Mania.Configuration new TrackedSetting(ManiaRulesetSetting.ScrollTime, scrollTime => new SettingDescription( rawValue: scrollTime, - name: "Scroll Speed", - value: $"{scrollTime}ms (speed {(int)Math.Round(DrawableManiaRuleset.MAX_TIME_RANGE / scrollTime)})" + name: RulesetSettingsStrings.ScrollSpeed, + value: RulesetSettingsStrings.ScrollSpeedTooltip(scrollTime, (int)Math.Round(DrawableManiaRuleset.MAX_TIME_RANGE / scrollTime)) ) ) }; From 1552726150f2c6481f81a3d4b4f83022079aded2 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 16 Jan 2023 14:03:09 +0300 Subject: [PATCH 110/376] Fix intermittent failure in beatmap options state test --- osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index cfee02dfb8..a61171abad 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -1064,6 +1064,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddAssert("options enabled", () => songSelect.ChildrenOfType().Single().Enabled.Value); AddStep("delete all beatmaps", () => manager.Delete()); + AddWaitStep("wait for debounce", 1); AddAssert("options disabled", () => !songSelect.ChildrenOfType().Single().Enabled.Value); } From fd5fac507e2fd3c07ffd4285a56ab1d4498662c7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Jan 2023 19:34:59 +0900 Subject: [PATCH 111/376] Add test coverage of expected touch to action handling --- .../TestSceneTouchInput.cs | 217 ++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs new file mode 100644 index 0000000000..b1edafa4f8 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs @@ -0,0 +1,217 @@ +// 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.Input; +using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; +using osu.Framework.Testing; +using osu.Game.Screens.Play; +using osu.Game.Tests.Visual; +using osuTK; + +namespace osu.Game.Rulesets.Osu.Tests +{ + [TestFixture] + public partial class TestSceneTouchInput : OsuManualInputManagerTestScene + { + private TestActionKeyCounter leftKeyCounter = null!; + + private TestActionKeyCounter rightKeyCounter = null!; + + private OsuInputManager osuInputManager = null!; + + [SetUpSteps] + public void SetUpSteps() + { + releaseAllTouches(); + + AddStep("Create tests", () => + { + Child = osuInputManager = new OsuInputManager(new OsuRuleset().RulesetInfo) + { + Child = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Children = new Drawable[] + { + leftKeyCounter = new TestActionKeyCounter(OsuAction.LeftButton), + rightKeyCounter = new TestActionKeyCounter(OsuAction.RightButton) { Margin = new MarginPadding { Left = 150 } } + }, + } + }; + }); + } + + [Test] + public void TestSimpleInput() + { + beginTouch(TouchSource.Touch1); + + assertKeyCounter(1, 0); + expectPressedCurrently(OsuAction.LeftButton); + + beginTouch(TouchSource.Touch2); + + assertKeyCounter(1, 1); + expectPressedCurrently(OsuAction.LeftButton); + expectPressedCurrently(OsuAction.RightButton); + + // Subsequent touches should be ignored. + beginTouch(TouchSource.Touch3); + beginTouch(TouchSource.Touch4); + + assertKeyCounter(1, 1); + + expectPressedCurrently(OsuAction.LeftButton); + expectPressedCurrently(OsuAction.RightButton); + + assertKeyCounter(1, 1); + } + + [Test] + public void TestAlternatingInput() + { + beginTouch(TouchSource.Touch1); + + assertKeyCounter(1, 0); + expectPressedCurrently(OsuAction.LeftButton); + + beginTouch(TouchSource.Touch2); + + assertKeyCounter(1, 1); + expectPressedCurrently(OsuAction.LeftButton); + expectPressedCurrently(OsuAction.RightButton); + + endTouch(TouchSource.Touch1); + + assertKeyCounter(1, 1); + expectPressedCurrently(OsuAction.RightButton); + + beginTouch(TouchSource.Touch1); + + assertKeyCounter(2, 1); + expectPressedCurrently(OsuAction.LeftButton); + expectPressedCurrently(OsuAction.RightButton); + + endTouch(TouchSource.Touch2); + + assertKeyCounter(2, 1); + expectPressedCurrently(OsuAction.LeftButton); + + beginTouch(TouchSource.Touch2); + + assertKeyCounter(2, 2); + expectPressedCurrently(OsuAction.LeftButton); + expectPressedCurrently(OsuAction.RightButton); + } + + [Test] + public void TestPressReleaseOrder() + { + beginTouch(TouchSource.Touch1); + beginTouch(TouchSource.Touch2); + beginTouch(TouchSource.Touch3); + + assertKeyCounter(1, 1); + expectPressedCurrently(OsuAction.LeftButton); + expectPressedCurrently(OsuAction.RightButton); + + // Touch 3 was ignored, but let's ensure that if 1 or 2 are released, 3 will be handled a second attempt. + endTouch(TouchSource.Touch1); + + assertKeyCounter(1, 1); + expectPressedCurrently(OsuAction.RightButton); + + endTouch(TouchSource.Touch3); + + assertKeyCounter(1, 1); + expectPressedCurrently(OsuAction.RightButton); + + beginTouch(TouchSource.Touch3); + + assertKeyCounter(2, 1); + expectPressedCurrently(OsuAction.LeftButton); + expectPressedCurrently(OsuAction.RightButton); + } + + [Test] + public void TestWithDisallowedUserCursor() + { + beginTouch(TouchSource.Touch1); + + assertKeyCounter(1, 0); + expectPressedCurrently(OsuAction.LeftButton); + + beginTouch(TouchSource.Touch2); + + assertKeyCounter(1, 1); + expectPressedCurrently(OsuAction.RightButton); + + // Subsequent touches should be ignored. + beginTouch(TouchSource.Touch3); + beginTouch(TouchSource.Touch4); + + assertKeyCounter(1, 1); + + expectPressedCurrently(OsuAction.LeftButton); + expectPressedCurrently(OsuAction.RightButton); + + assertKeyCounter(1, 1); + } + + private void beginTouch(TouchSource source, Vector2? screenSpacePosition = null) => + AddStep($"Begin touch for {source}", () => InputManager.BeginTouch(new Touch(source, screenSpacePosition ?? osuInputManager.ScreenSpaceDrawQuad.Centre))); + + private void endTouch(TouchSource source) => + AddStep($"Release touch for {source}", () => InputManager.EndTouch(new Touch(source, osuInputManager.ScreenSpaceDrawQuad.Centre))); + + private void assertKeyCounter(int left, int right) + { + AddAssert($"The left key was pressed {left} times", () => leftKeyCounter.CountPresses, () => Is.EqualTo(left)); + AddAssert($"The right key was pressed {right} times", () => rightKeyCounter.CountPresses, () => Is.EqualTo(right)); + } + + private void releaseAllTouches() + { + AddStep("Release all touches", () => + { + foreach (TouchSource source in InputManager.CurrentState.Touch.ActiveSources) + InputManager.EndTouch(new Touch(source, osuInputManager.ScreenSpaceDrawQuad.Centre)); + }); + } + + private void expectPressedCurrently(OsuAction action) => AddAssert($"Is pressing {action}", () => osuInputManager.PressedActions.Contains(action)); + + public partial class TestActionKeyCounter : KeyCounter, IKeyBindingHandler + { + public OsuAction Action { get; } + + public TestActionKeyCounter(OsuAction action) + : base(action.ToString()) + { + Action = action; + } + + public bool OnPressed(KeyBindingPressEvent e) + { + if (e.Action == Action) + { + IsLit = true; + Increment(); + } + + return false; + } + + public void OnReleased(KeyBindingReleaseEvent e) + { + if (e.Action == Action) IsLit = false; + } + } + } +} From b265888f182935035a372d5f6558f8895b90b2c5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Jan 2023 19:35:55 +0900 Subject: [PATCH 112/376] Add bare minimum touch support to osu! ruleset --- osu.Game.Rulesets.Osu/OsuInputManager.cs | 11 ++- .../UI/OsuTouchInputMapper.cs | 76 +++++++++++++++++++ 2 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs diff --git a/osu.Game.Rulesets.Osu/OsuInputManager.cs b/osu.Game.Rulesets.Osu/OsuInputManager.cs index 7dede9e283..28b4f70c10 100644 --- a/osu.Game.Rulesets.Osu/OsuInputManager.cs +++ b/osu.Game.Rulesets.Osu/OsuInputManager.cs @@ -1,16 +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.Collections.Generic; using System.ComponentModel; using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Input.StateChanges.Events; using osu.Game.Input.Bindings; +using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Osu @@ -45,6 +46,12 @@ namespace osu.Game.Rulesets.Osu { } + [BackgroundDependencyLoader] + private void load() + { + Add(new OsuTouchInputMapper(this) { RelativeSizeAxes = Axes.Both }); + } + protected override bool Handle(UIEvent e) { if ((e is MouseMoveEvent || e is TouchMoveEvent) && !AllowUserCursorMovement) return false; diff --git a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs new file mode 100644 index 0000000000..f4ed70f790 --- /dev/null +++ b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs @@ -0,0 +1,76 @@ +// 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.Graphics; +using osu.Framework.Input; +using osu.Framework.Input.Events; + +namespace osu.Game.Rulesets.Osu.UI +{ + public partial class OsuTouchInputMapper : Drawable + { + /// + /// This is our parent . + /// + private readonly OsuInputManager osuInputManager; + + /// + /// All the active s and the that it triggered (if any). + /// Ordered from oldest to newest touch chronologically. + /// + private readonly List trackedTouches = new List(); + + public OsuTouchInputMapper(OsuInputManager inputManager) + { + osuInputManager = inputManager; + } + + private OsuAction? lastAction; + + protected override bool OnTouchDown(TouchDownEvent e) + { + OsuAction action = lastAction == OsuAction.LeftButton && trackedTouches.Count > 0 ? OsuAction.RightButton : OsuAction.LeftButton; + + if (trackedTouches.All(t => t.Action != action)) + { + trackedTouches.Add(new TrackedTouch(e.Touch, action)); + osuInputManager.KeyBindingContainer.TriggerPressed(action); + lastAction = action; + } + else + { + // Ignore any taps which trigger an action which is already handled. But track them for potential positional input in the future. + trackedTouches.Add(new TrackedTouch(e.Touch, null)); + } + + return true; + } + + protected override void OnTouchUp(TouchUpEvent e) + { + var tracked = trackedTouches.First(t => t.Touch.Source == e.Touch.Source); + + if (tracked.Action is OsuAction action) + osuInputManager.KeyBindingContainer.TriggerReleased(action); + + trackedTouches.Remove(tracked); + + base.OnTouchUp(e); + } + + private class TrackedTouch + { + public readonly Touch Touch; + + public readonly OsuAction? Action; + + public TrackedTouch(Touch touch, OsuAction? action) + { + Touch = touch; + Action = action; + } + } + } +} From 355bec2058217ae28cc683d2a1edd030dade305e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Jan 2023 20:11:59 +0900 Subject: [PATCH 113/376] Handle movement locally as we are blocking events from touch->mouse mapping --- .../UI/OsuTouchInputMapper.cs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs index f4ed70f790..a57953f8d3 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs @@ -6,6 +6,7 @@ using System.Linq; using osu.Framework.Graphics; using osu.Framework.Input; using osu.Framework.Input.Events; +using osu.Framework.Input.StateChanges; namespace osu.Game.Rulesets.Osu.UI { @@ -27,17 +28,24 @@ namespace osu.Game.Rulesets.Osu.UI osuInputManager = inputManager; } - private OsuAction? lastAction; + protected override void OnTouchMove(TouchMoveEvent e) + { + base.OnTouchMove(e); + handleTouchMovement(e); + } protected override bool OnTouchDown(TouchDownEvent e) { - OsuAction action = lastAction == OsuAction.LeftButton && trackedTouches.Count > 0 ? OsuAction.RightButton : OsuAction.LeftButton; + OsuAction action = trackedTouches.Any(t => t.Action == OsuAction.LeftButton) + ? OsuAction.RightButton + : OsuAction.LeftButton; + + handleTouchMovement(e); if (trackedTouches.All(t => t.Action != action)) { trackedTouches.Add(new TrackedTouch(e.Touch, action)); osuInputManager.KeyBindingContainer.TriggerPressed(action); - lastAction = action; } else { @@ -48,6 +56,11 @@ namespace osu.Game.Rulesets.Osu.UI return true; } + private void handleTouchMovement(TouchEvent touchEvent) + { + new MousePositionAbsoluteInput { Position = touchEvent.ScreenSpaceTouch.Position }.Apply(osuInputManager.CurrentState, osuInputManager); + } + protected override void OnTouchUp(TouchUpEvent e) { var tracked = trackedTouches.First(t => t.Touch.Source == e.Touch.Source); From 606e374d94782738f3d6946da59692796aeb36f3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Jan 2023 20:13:31 +0900 Subject: [PATCH 114/376] Don't handle touch down events if "mouse" buttons are disabled Maintains compatibility with existing logic. --- osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs index a57953f8d3..16283d3baa 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs @@ -3,10 +3,13 @@ using System.Collections.Generic; using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Input; using osu.Framework.Input.Events; using osu.Framework.Input.StateChanges; +using osu.Game.Configuration; namespace osu.Game.Rulesets.Osu.UI { @@ -23,11 +26,19 @@ namespace osu.Game.Rulesets.Osu.UI /// private readonly List trackedTouches = new List(); + private Bindable mouseDisabled = null!; + public OsuTouchInputMapper(OsuInputManager inputManager) { osuInputManager = inputManager; } + [BackgroundDependencyLoader(true)] + private void load(OsuConfigManager config) + { + mouseDisabled = config.GetBindable(OsuSetting.MouseDisableButtons); + } + protected override void OnTouchMove(TouchMoveEvent e) { base.OnTouchMove(e); @@ -42,7 +53,7 @@ namespace osu.Game.Rulesets.Osu.UI handleTouchMovement(e); - if (trackedTouches.All(t => t.Action != action)) + if (!mouseDisabled.Value && trackedTouches.All(t => t.Action != action)) { trackedTouches.Add(new TrackedTouch(e.Touch, action)); osuInputManager.KeyBindingContainer.TriggerPressed(action); From b1c9505ab6216c667e276c33b691ef54af8ba14d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Jan 2023 20:45:04 +0900 Subject: [PATCH 115/376] Add touch visualisation to test --- .../TestSceneTouchInput.cs | 123 ++++++++++++++++-- 1 file changed, 111 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs index b1edafa4f8..fc39c6493d 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs @@ -1,17 +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 System.Diagnostics; using System.Linq; using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; +using osu.Framework.Input.States; using osu.Framework.Testing; using osu.Game.Screens.Play; using osu.Game.Tests.Visual; using osuTK; +using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Tests { @@ -31,18 +35,32 @@ namespace osu.Game.Rulesets.Osu.Tests AddStep("Create tests", () => { - Child = osuInputManager = new OsuInputManager(new OsuRuleset().RulesetInfo) + Children = new Drawable[] { - Child = new Container + osuInputManager = new OsuInputManager(new OsuRuleset().RulesetInfo) { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Children = new Drawable[] + Child = new Container { - leftKeyCounter = new TestActionKeyCounter(OsuAction.LeftButton), - rightKeyCounter = new TestActionKeyCounter(OsuAction.RightButton) { Margin = new MarginPadding { Left = 150 } } - }, - } + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Children = new Drawable[] + { + leftKeyCounter = new TestActionKeyCounter(OsuAction.LeftButton) + { + Anchor = Anchor.Centre, + Origin = Anchor.CentreRight, + X = -100, + }, + rightKeyCounter = new TestActionKeyCounter(OsuAction.RightButton) + { + Anchor = Anchor.Centre, + Origin = Anchor.CentreLeft, + X = 100, + } + }, + } + }, + new TouchVisualiser(), }; }); } @@ -165,10 +183,18 @@ namespace osu.Game.Rulesets.Osu.Tests } private void beginTouch(TouchSource source, Vector2? screenSpacePosition = null) => - AddStep($"Begin touch for {source}", () => InputManager.BeginTouch(new Touch(source, screenSpacePosition ?? osuInputManager.ScreenSpaceDrawQuad.Centre))); + AddStep($"Begin touch for {source}", () => InputManager.BeginTouch(new Touch(source, screenSpacePosition ??= getSanePositionForSource(source)))); - private void endTouch(TouchSource source) => - AddStep($"Release touch for {source}", () => InputManager.EndTouch(new Touch(source, osuInputManager.ScreenSpaceDrawQuad.Centre))); + private void endTouch(TouchSource source, Vector2? screenSpacePosition = null) => + AddStep($"Release touch for {source}", () => InputManager.EndTouch(new Touch(source, screenSpacePosition ??= getSanePositionForSource(source)))); + + private Vector2 getSanePositionForSource(TouchSource source) + { + return new Vector2( + osuInputManager.ScreenSpaceDrawQuad.Centre.X + osuInputManager.ScreenSpaceDrawQuad.Width * (-1 + (int)source) / 8, + osuInputManager.ScreenSpaceDrawQuad.Centre.Y - 100 + ); + } private void assertKeyCounter(int left, int right) { @@ -213,5 +239,78 @@ namespace osu.Game.Rulesets.Osu.Tests if (e.Action == Action) IsLit = false; } } + + public partial class TouchVisualiser : CompositeDrawable + { + private readonly Drawable?[] drawableTouches = new Drawable?[10]; + + public TouchVisualiser() + { + RelativeSizeAxes = Axes.Both; + } + + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; + + protected override bool OnTouchDown(TouchDownEvent e) + { + if (IsDisposed) + return false; + + var circle = new Circle + { + Alpha = 0.5f, + Origin = Anchor.Centre, + Size = new Vector2(20), + Position = e.Touch.Position, + Colour = colourFor(e.Touch.Source), + }; + + AddInternal(circle); + drawableTouches[(int)e.Touch.Source] = circle; + return false; + } + + protected override void OnTouchMove(TouchMoveEvent e) + { + if (IsDisposed) + return; + + var circle = drawableTouches[(int)e.Touch.Source]; + + Debug.Assert(circle != null); + + AddInternal(new FadingCircle(circle)); + circle.Position = e.Touch.Position; + } + + protected override void OnTouchUp(TouchUpEvent e) + { + var circle = drawableTouches[(int)e.Touch.Source]; + circle.FadeOut(200, Easing.OutQuint).Expire(); + drawableTouches[(int)e.Touch.Source] = null; + } + + private Color4 colourFor(TouchSource source) + { + return Color4.FromHsv(new Vector4((float)source / TouchState.MAX_TOUCH_COUNT, 1f, 1f, 1f)); + } + + private partial class FadingCircle : Circle + { + public FadingCircle(Drawable source) + { + Origin = Anchor.Centre; + Size = source.Size; + Position = source.Position; + Colour = source.Colour; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + this.FadeOut(200).Expire(); + } + } + } } } From 9c5789848f0976c5ac7232abd7ebea04c12dd44c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Jan 2023 20:55:53 +0900 Subject: [PATCH 116/376] Add further coverage of alternating Covers a real failure I discovered. --- .../TestSceneTouchInput.cs | 68 ++++++++++--------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs index fc39c6493d..9860026b49 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs @@ -71,13 +71,13 @@ namespace osu.Game.Rulesets.Osu.Tests beginTouch(TouchSource.Touch1); assertKeyCounter(1, 0); - expectPressedCurrently(OsuAction.LeftButton); + checkPressed(OsuAction.LeftButton); beginTouch(TouchSource.Touch2); assertKeyCounter(1, 1); - expectPressedCurrently(OsuAction.LeftButton); - expectPressedCurrently(OsuAction.RightButton); + checkPressed(OsuAction.LeftButton); + checkPressed(OsuAction.RightButton); // Subsequent touches should be ignored. beginTouch(TouchSource.Touch3); @@ -85,8 +85,8 @@ namespace osu.Game.Rulesets.Osu.Tests assertKeyCounter(1, 1); - expectPressedCurrently(OsuAction.LeftButton); - expectPressedCurrently(OsuAction.RightButton); + checkPressed(OsuAction.LeftButton); + checkPressed(OsuAction.RightButton); assertKeyCounter(1, 1); } @@ -97,35 +97,36 @@ namespace osu.Game.Rulesets.Osu.Tests beginTouch(TouchSource.Touch1); assertKeyCounter(1, 0); - expectPressedCurrently(OsuAction.LeftButton); + checkPressed(OsuAction.LeftButton); beginTouch(TouchSource.Touch2); assertKeyCounter(1, 1); - expectPressedCurrently(OsuAction.LeftButton); - expectPressedCurrently(OsuAction.RightButton); + checkPressed(OsuAction.LeftButton); + checkPressed(OsuAction.RightButton); - endTouch(TouchSource.Touch1); + for (int i = 0; i < 2; i++) + { + endTouch(TouchSource.Touch1); - assertKeyCounter(1, 1); - expectPressedCurrently(OsuAction.RightButton); + checkPressed(OsuAction.RightButton); + checkNotPressed(OsuAction.LeftButton); - beginTouch(TouchSource.Touch1); + beginTouch(TouchSource.Touch1); - assertKeyCounter(2, 1); - expectPressedCurrently(OsuAction.LeftButton); - expectPressedCurrently(OsuAction.RightButton); + checkPressed(OsuAction.LeftButton); + checkPressed(OsuAction.RightButton); - endTouch(TouchSource.Touch2); + endTouch(TouchSource.Touch2); - assertKeyCounter(2, 1); - expectPressedCurrently(OsuAction.LeftButton); + checkPressed(OsuAction.LeftButton); + checkNotPressed(OsuAction.RightButton); - beginTouch(TouchSource.Touch2); + beginTouch(TouchSource.Touch2); - assertKeyCounter(2, 2); - expectPressedCurrently(OsuAction.LeftButton); - expectPressedCurrently(OsuAction.RightButton); + checkPressed(OsuAction.LeftButton); + checkPressed(OsuAction.RightButton); + } } [Test] @@ -136,25 +137,25 @@ namespace osu.Game.Rulesets.Osu.Tests beginTouch(TouchSource.Touch3); assertKeyCounter(1, 1); - expectPressedCurrently(OsuAction.LeftButton); - expectPressedCurrently(OsuAction.RightButton); + checkPressed(OsuAction.LeftButton); + checkPressed(OsuAction.RightButton); // Touch 3 was ignored, but let's ensure that if 1 or 2 are released, 3 will be handled a second attempt. endTouch(TouchSource.Touch1); assertKeyCounter(1, 1); - expectPressedCurrently(OsuAction.RightButton); + checkPressed(OsuAction.RightButton); endTouch(TouchSource.Touch3); assertKeyCounter(1, 1); - expectPressedCurrently(OsuAction.RightButton); + checkPressed(OsuAction.RightButton); beginTouch(TouchSource.Touch3); assertKeyCounter(2, 1); - expectPressedCurrently(OsuAction.LeftButton); - expectPressedCurrently(OsuAction.RightButton); + checkPressed(OsuAction.LeftButton); + checkPressed(OsuAction.RightButton); } [Test] @@ -163,12 +164,12 @@ namespace osu.Game.Rulesets.Osu.Tests beginTouch(TouchSource.Touch1); assertKeyCounter(1, 0); - expectPressedCurrently(OsuAction.LeftButton); + checkPressed(OsuAction.LeftButton); beginTouch(TouchSource.Touch2); assertKeyCounter(1, 1); - expectPressedCurrently(OsuAction.RightButton); + checkPressed(OsuAction.RightButton); // Subsequent touches should be ignored. beginTouch(TouchSource.Touch3); @@ -176,8 +177,8 @@ namespace osu.Game.Rulesets.Osu.Tests assertKeyCounter(1, 1); - expectPressedCurrently(OsuAction.LeftButton); - expectPressedCurrently(OsuAction.RightButton); + checkPressed(OsuAction.LeftButton); + checkPressed(OsuAction.RightButton); assertKeyCounter(1, 1); } @@ -211,7 +212,8 @@ namespace osu.Game.Rulesets.Osu.Tests }); } - private void expectPressedCurrently(OsuAction action) => AddAssert($"Is pressing {action}", () => osuInputManager.PressedActions.Contains(action)); + private void checkNotPressed(OsuAction action) => AddAssert($"Not pressing {action}", () => !osuInputManager.PressedActions.Contains(action)); + private void checkPressed(OsuAction action) => AddAssert($"Is pressing {action}", () => osuInputManager.PressedActions.Contains(action)); public partial class TestActionKeyCounter : KeyCounter, IKeyBindingHandler { From eaaab2e76dcda4ca24b1ba5b42b6b58e76f025b0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Jan 2023 20:58:24 +0900 Subject: [PATCH 117/376] Add test coverage of disabled mouse buttons --- .../TestSceneTouchInput.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs index 9860026b49..01b54d97a7 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Linq; using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -12,6 +13,7 @@ using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Input.States; using osu.Framework.Testing; +using osu.Game.Configuration; using osu.Game.Screens.Play; using osu.Game.Tests.Visual; using osuTK; @@ -22,6 +24,9 @@ namespace osu.Game.Rulesets.Osu.Tests [TestFixture] public partial class TestSceneTouchInput : OsuManualInputManagerTestScene { + [Resolved] + private OsuConfigManager config { get; set; } = null!; + private TestActionKeyCounter leftKeyCounter = null!; private TestActionKeyCounter rightKeyCounter = null!; @@ -91,6 +96,23 @@ namespace osu.Game.Rulesets.Osu.Tests assertKeyCounter(1, 1); } + [Test] + public void TestSimpleInputButtonsDisabled() + { + AddStep("Disable mouse buttons", () => config.SetValue(OsuSetting.MouseDisableButtons, true)); + + beginTouch(TouchSource.Touch1); + + assertKeyCounter(0, 0); + checkNotPressed(OsuAction.LeftButton); + + beginTouch(TouchSource.Touch2); + + assertKeyCounter(0, 0); + checkNotPressed(OsuAction.LeftButton); + checkNotPressed(OsuAction.RightButton); + } + [Test] public void TestAlternatingInput() { @@ -207,6 +229,7 @@ namespace osu.Game.Rulesets.Osu.Tests { AddStep("Release all touches", () => { + config.SetValue(OsuSetting.MouseDisableButtons, false); foreach (TouchSource source in InputManager.CurrentState.Touch.ActiveSources) InputManager.EndTouch(new Touch(source, osuInputManager.ScreenSpaceDrawQuad.Centre)); }); From ab3d63211211d79e37a05a19b955dfcc00912f3e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Jan 2023 21:02:37 +0900 Subject: [PATCH 118/376] Also add test coverage of positional updates --- osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs index 01b54d97a7..0f27579975 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs @@ -77,16 +77,21 @@ namespace osu.Game.Rulesets.Osu.Tests assertKeyCounter(1, 0); checkPressed(OsuAction.LeftButton); + checkPosition(TouchSource.Touch1); beginTouch(TouchSource.Touch2); assertKeyCounter(1, 1); checkPressed(OsuAction.LeftButton); checkPressed(OsuAction.RightButton); + checkPosition(TouchSource.Touch2); - // Subsequent touches should be ignored. + // Subsequent touches should be ignored (except position). beginTouch(TouchSource.Touch3); + checkPosition(TouchSource.Touch3); + beginTouch(TouchSource.Touch4); + checkPosition(TouchSource.Touch4); assertKeyCounter(1, 1); @@ -105,12 +110,14 @@ namespace osu.Game.Rulesets.Osu.Tests assertKeyCounter(0, 0); checkNotPressed(OsuAction.LeftButton); + checkPosition(TouchSource.Touch1); beginTouch(TouchSource.Touch2); assertKeyCounter(0, 0); checkNotPressed(OsuAction.LeftButton); checkNotPressed(OsuAction.RightButton); + checkPosition(TouchSource.Touch2); } [Test] @@ -219,6 +226,9 @@ namespace osu.Game.Rulesets.Osu.Tests ); } + private void checkPosition(TouchSource touchSource) => + AddAssert("Cursor position is correct", () => osuInputManager.CurrentState.Mouse.Position, () => Is.EqualTo(getSanePositionForSource(touchSource))); + private void assertKeyCounter(int left, int right) { AddAssert($"The left key was pressed {left} times", () => leftKeyCounter.CountPresses, () => Is.EqualTo(left)); From 6b16d3ee6191370551f87c1e1bac9a6f6872cae3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Jan 2023 21:07:19 +0900 Subject: [PATCH 119/376] Add test expectation for how positional input should be handled --- .../TestSceneTouchInput.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs index 0f27579975..5452405bf0 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs @@ -101,6 +101,26 @@ namespace osu.Game.Rulesets.Osu.Tests assertKeyCounter(1, 1); } + [Test] + public void TestPositionalInputUpdatesOnlyFromMostRecentTouch() + { + beginTouch(TouchSource.Touch1); + checkPosition(TouchSource.Touch1); + + beginTouch(TouchSource.Touch2); + checkPosition(TouchSource.Touch2); + + beginTouch(TouchSource.Touch1, Vector2.One); + checkPosition(TouchSource.Touch2); + + endTouch(TouchSource.Touch2); + checkPosition(TouchSource.Touch2); + + // note that touch1 was never ended, but becomes active for tracking again. + beginTouch(TouchSource.Touch1); + checkPosition(TouchSource.Touch1); + } + [Test] public void TestSimpleInputButtonsDisabled() { From b3860c6d52682d331fc34f6ecf4ab959dffe79cd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Jan 2023 21:07:28 +0900 Subject: [PATCH 120/376] Only use positional input from most recent touch --- .../UI/OsuTouchInputMapper.cs | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs index 16283d3baa..38dbde99b9 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs @@ -51,24 +51,26 @@ namespace osu.Game.Rulesets.Osu.UI ? OsuAction.RightButton : OsuAction.LeftButton; + // Ignore any taps which trigger an action which is already handled. But track them for potential positional input in the future. + bool shouldResultInAction = !mouseDisabled.Value && trackedTouches.All(t => t.Action != action); + + trackedTouches.Add(new TrackedTouch(e.Touch, shouldResultInAction ? action : null)); + + // Important to update position before triggering the pressed action. handleTouchMovement(e); - if (!mouseDisabled.Value && trackedTouches.All(t => t.Action != action)) - { - trackedTouches.Add(new TrackedTouch(e.Touch, action)); + if (shouldResultInAction) osuInputManager.KeyBindingContainer.TriggerPressed(action); - } - else - { - // Ignore any taps which trigger an action which is already handled. But track them for potential positional input in the future. - trackedTouches.Add(new TrackedTouch(e.Touch, null)); - } return true; } private void handleTouchMovement(TouchEvent touchEvent) { + // Movement should only be tracked for the most recent touch. + if (touchEvent.Touch != trackedTouches.Last().Touch) + return; + new MousePositionAbsoluteInput { Position = touchEvent.ScreenSpaceTouch.Position }.Apply(osuInputManager.CurrentState, osuInputManager); } From 26f3b1dbfee45ed20d9bc62f003832f8bfca92c8 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 16 Jan 2023 19:37:47 +0300 Subject: [PATCH 121/376] Localise "revert to default" tooltip --- osu.Game/Localisation/CommonStrings.cs | 5 +++++ osu.Game/Overlays/RestoreDefaultValueButton.cs | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Localisation/CommonStrings.cs b/osu.Game/Localisation/CommonStrings.cs index 10178915a2..fed7b6cab7 100644 --- a/osu.Game/Localisation/CommonStrings.cs +++ b/osu.Game/Localisation/CommonStrings.cs @@ -154,6 +154,11 @@ namespace osu.Game.Localisation /// public static LocalisableString Exit => new TranslatableString(getKey(@"exit"), @"Exit"); + /// + /// "Revert to default" + /// + public static LocalisableString RevertToDefault => new TranslatableString(getKey(@"revert_to_default"), @"Revert to default"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs index 9d5e5db6e6..97c66fdf02 100644 --- a/osu.Game/Overlays/RestoreDefaultValueButton.cs +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; @@ -17,6 +18,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osuTK; +using osu.Game.Localisation; namespace osu.Game.Overlays { @@ -96,7 +98,7 @@ namespace osu.Game.Overlays FinishTransforms(true); } - public override LocalisableString TooltipText => "revert to default"; + public override LocalisableString TooltipText => CommonStrings.RevertToDefault.ToLower(); protected override bool OnHover(HoverEvent e) { From 6eb5508404c5841fc0dc007bc9224efc8df0c55b Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 16 Jan 2023 19:39:50 +0300 Subject: [PATCH 122/376] Localise menu bar --- osu.Game/Skinning/Editor/SkinEditor.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Skinning/Editor/SkinEditor.cs b/osu.Game/Skinning/Editor/SkinEditor.cs index 0ed4e5afd2..5fe92b33aa 100644 --- a/osu.Game/Skinning/Editor/SkinEditor.cs +++ b/osu.Game/Skinning/Editor/SkinEditor.cs @@ -122,14 +122,14 @@ namespace osu.Game.Skinning.Editor RelativeSizeAxes = Axes.Both, Items = new[] { - new MenuItem("File") + new MenuItem(CommonStrings.MenuBarFile) { Items = new[] { - new EditorMenuItem("Save", MenuItemType.Standard, Save), - new EditorMenuItem("Revert to default", MenuItemType.Destructive, revert), + new EditorMenuItem(Resources.Localisation.Web.CommonStrings.ButtonsSave, MenuItemType.Standard, Save), + new EditorMenuItem(CommonStrings.RevertToDefault, MenuItemType.Destructive, revert), new EditorMenuItemSpacer(), - new EditorMenuItem("Exit", MenuItemType.Standard, () => skinEditorOverlay?.Hide()), + new EditorMenuItem(CommonStrings.Exit, MenuItemType.Standard, () => skinEditorOverlay?.Hide()), }, }, } From 17aeb0ec192b13e158233d2f299fabe759d61794 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 16 Jan 2023 19:55:28 +0300 Subject: [PATCH 123/376] Localise editor's UI --- osu.Game/Localisation/SkinEditorStrings.cs | 49 +++++++++++++++++++ .../Skinning/Editor/SkinComponentToolbox.cs | 3 +- osu.Game/Skinning/Editor/SkinEditor.cs | 9 ++-- .../Skinning/Editor/SkinEditorSceneLibrary.cs | 9 ++-- .../Skinning/Editor/SkinSettingsToolbox.cs | 5 +- 5 files changed, 62 insertions(+), 13 deletions(-) create mode 100644 osu.Game/Localisation/SkinEditorStrings.cs diff --git a/osu.Game/Localisation/SkinEditorStrings.cs b/osu.Game/Localisation/SkinEditorStrings.cs new file mode 100644 index 0000000000..605b7d6a9d --- /dev/null +++ b/osu.Game/Localisation/SkinEditorStrings.cs @@ -0,0 +1,49 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Localisation; + +namespace osu.Game.Localisation +{ + public static class SkinEditorStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.SkinEditor"; + + /// + /// "Skin editor" + /// + public static LocalisableString SkinEditor => new TranslatableString(getKey(@"skin_editor"), @"Skin editor"); + + /// + /// "Currently editing" + /// + public static LocalisableString CurrentlyEditing => new TranslatableString(getKey(@"currently_editing"), @"Currently editing"); + + /// + /// "Components" + /// + public static LocalisableString Components => new TranslatableString(getKey(@"components"), @"Components"); + + /// + /// "Scene library" + /// + public static LocalisableString SceneLibrary => new TranslatableString(getKey(@"scene_library"), @"Scene library"); + + /// + /// "Song Select" + /// + public static LocalisableString SongSelect => new TranslatableString(getKey(@"song_select"), @"Song Select"); + + /// + /// "Gameplay" + /// + public static LocalisableString Gameplay => new TranslatableString(getKey(@"gameplay"), @"Gameplay"); + + /// + /// "Settings ({0})" + /// + public static LocalisableString Settings(string arg0) => new TranslatableString(getKey(@"settings"), @"Settings ({0})", arg0); + + private static string getKey(string key) => $@"{prefix}:{key}"; + } +} diff --git a/osu.Game/Skinning/Editor/SkinComponentToolbox.cs b/osu.Game/Skinning/Editor/SkinComponentToolbox.cs index 053119557f..9985b81059 100644 --- a/osu.Game/Skinning/Editor/SkinComponentToolbox.cs +++ b/osu.Game/Skinning/Editor/SkinComponentToolbox.cs @@ -10,6 +10,7 @@ using osu.Framework.Logging; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Overlays; using osu.Game.Screens.Edit.Components; using osu.Game.Screens.Play.HUD; @@ -26,7 +27,7 @@ namespace osu.Game.Skinning.Editor private FillFlowContainer fill = null!; public SkinComponentToolbox(CompositeDrawable? target = null) - : base("Components") + : base(SkinEditorStrings.Components) { this.target = target; } diff --git a/osu.Game/Skinning/Editor/SkinEditor.cs b/osu.Game/Skinning/Editor/SkinEditor.cs index 5fe92b33aa..74391e5269 100644 --- a/osu.Game/Skinning/Editor/SkinEditor.cs +++ b/osu.Game/Skinning/Editor/SkinEditor.cs @@ -109,7 +109,7 @@ namespace osu.Game.Skinning.Editor { new Container { - Name = "Menu container", + Name = @"Menu container", RelativeSizeAxes = Axes.X, Depth = float.MinValue, Height = MENU_HEIGHT, @@ -234,7 +234,6 @@ 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); @@ -253,15 +252,15 @@ namespace osu.Game.Skinning.Editor { headerText.Clear(); - headerText.AddParagraph("Skin editor", cp => cp.Font = OsuFont.Default.With(size: 16)); + headerText.AddParagraph(SkinEditorStrings.SkinEditor, cp => cp.Font = OsuFont.Default.With(size: 16)); headerText.NewParagraph(); - headerText.AddText("Currently editing ", cp => + headerText.AddText(SkinEditorStrings.CurrentlyEditing, cp => { cp.Font = OsuFont.Default.With(size: 12); cp.Colour = colours.Yellow; }); - headerText.AddText($"{currentSkin.Value.SkinInfo}", cp => + headerText.AddText($" {currentSkin.Value.SkinInfo}", cp => { cp.Font = OsuFont.Default.With(size: 12, weight: FontWeight.Bold); cp.Colour = colours.Yellow; diff --git a/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs b/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs index c3907ea60d..44045e8916 100644 --- a/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs +++ b/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs @@ -16,6 +16,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Overlays; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; @@ -66,7 +67,7 @@ namespace osu.Game.Skinning.Editor { new FillFlowContainer { - Name = "Scene library", + Name = @"Scene library", AutoSizeAxes = Axes.X, RelativeSizeAxes = Axes.Y, Spacing = new Vector2(padding), @@ -76,14 +77,14 @@ namespace osu.Game.Skinning.Editor { new OsuSpriteText { - Text = "Scene library", + Text = SkinEditorStrings.SceneLibrary, Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Margin = new MarginPadding(10), }, new SceneButton { - Text = "Song Select", + Text = SkinEditorStrings.SongSelect, Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Action = () => performer?.PerformFromScreen(screen => @@ -96,7 +97,7 @@ namespace osu.Game.Skinning.Editor }, new SceneButton { - Text = "Gameplay", + Text = SkinEditorStrings.Gameplay, Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Action = () => performer?.PerformFromScreen(screen => diff --git a/osu.Game/Skinning/Editor/SkinSettingsToolbox.cs b/osu.Game/Skinning/Editor/SkinSettingsToolbox.cs index 8c08f40b70..6afe92c6b2 100644 --- a/osu.Game/Skinning/Editor/SkinSettingsToolbox.cs +++ b/osu.Game/Skinning/Editor/SkinSettingsToolbox.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 System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Configuration; +using osu.Game.Localisation; using osu.Game.Screens.Edit.Components; using osuTK; @@ -17,7 +16,7 @@ namespace osu.Game.Skinning.Editor protected override Container Content { get; } public SkinSettingsToolbox(Drawable component) - : base($"Settings ({component.GetType().Name})") + : base(SkinEditorStrings.Settings(component.GetType().Name)) { base.Content.Add(Content = new FillFlowContainer { From 1a776eb546119761f1f1283956c65a5b4fae1347 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 12 Jan 2023 14:36:56 +0300 Subject: [PATCH 124/376] Mark item-mutating queue mode tests with `FlakyTest` attribute --- .../TestSceneAllPlayersQueueMode.cs | 33 ++++++--- .../Multiplayer/TestSceneHostOnlyQueueMode.cs | 71 +++++++++++-------- 2 files changed, 64 insertions(+), 40 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs index 7b1abd104f..6da9d37648 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs @@ -34,6 +34,24 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + public void TestSingleItemExpiredAfterGameplay() + { + RunGameplay(); + + AddUntilStep("playlist has only one item", () => MultiplayerClient.ClientAPIRoom?.Playlist.Count == 1); + AddUntilStep("playlist item is expired", () => MultiplayerClient.ClientAPIRoom?.Playlist[0].Expired == true); + AddUntilStep("last item selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID); + } + + [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); @@ -46,16 +64,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] - public void TestSingleItemExpiredAfterGameplay() - { - RunGameplay(); - - AddUntilStep("playlist has only one item", () => MultiplayerClient.ClientAPIRoom?.Playlist.Count == 1); - AddUntilStep("playlist item is expired", () => MultiplayerClient.ClientAPIRoom?.Playlist[0].Expired == true); - AddUntilStep("last item selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID); - } - - [Test] + [FlakyTest] // See above public void TestNextItemSelectedAfterGameplayFinish() { addItem(() => OtherBeatmap); @@ -73,6 +82,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestItemsNotClearedWhenSwitchToHostOnlyMode() { addItem(() => OtherBeatmap); @@ -88,6 +98,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestCorrectItemSelectedAfterNewItemAdded() { addItem(() => OtherBeatmap); @@ -95,6 +106,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestCorrectRulesetSelectedAfterNewItemAdded() { addItem(() => OtherBeatmap, new CatchRuleset().RulesetInfo); @@ -112,6 +124,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestCorrectModsSelectedAfterNewItemAdded() { addItem(() => OtherBeatmap, mods: new Mod[] { new OsuModDoubleTime() }); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs index 145c655c0a..dc36f539e3 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs @@ -27,22 +27,6 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("first item selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID); } - [Test] - public void TestItemStillSelectedAfterChangeToSameBeatmap() - { - selectNewItem(() => InitialBeatmap); - - AddUntilStep("playlist item still selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID); - } - - [Test] - public void TestItemStillSelectedAfterChangeToOtherBeatmap() - { - selectNewItem(() => OtherBeatmap); - - AddUntilStep("playlist item still selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID); - } - [Test] public void TestNewItemCreatedAfterGameplayFinished() { @@ -54,20 +38,6 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("second playlist item selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[1].ID); } - [Test] - public void TestOnlyLastItemChangedAfterGameplayFinished() - { - RunGameplay(); - - IBeatmapInfo firstBeatmap = null; - AddStep("get first playlist item beatmap", () => firstBeatmap = MultiplayerClient.ServerAPIRoom?.Playlist[0].Beatmap); - - selectNewItem(() => OtherBeatmap); - - AddUntilStep("first playlist item hasn't changed", () => MultiplayerClient.ServerAPIRoom?.Playlist[0].Beatmap == firstBeatmap); - AddUntilStep("second playlist item changed", () => MultiplayerClient.ClientAPIRoom?.Playlist[1].Beatmap != firstBeatmap); - } - [Test] public void TestSettingsUpdatedWhenChangingQueueMode() { @@ -80,6 +50,47 @@ 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); + + AddUntilStep("playlist item still selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID); + } + + [Test] + [FlakyTest] // See above + public void TestItemStillSelectedAfterChangeToOtherBeatmap() + { + selectNewItem(() => OtherBeatmap); + + AddUntilStep("playlist item still selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID); + } + + [Test] + [FlakyTest] // See above + public void TestOnlyLastItemChangedAfterGameplayFinished() + { + RunGameplay(); + + IBeatmapInfo firstBeatmap = null; + AddStep("get first playlist item beatmap", () => firstBeatmap = MultiplayerClient.ServerAPIRoom?.Playlist[0].Beatmap); + + selectNewItem(() => OtherBeatmap); + + AddUntilStep("first playlist item hasn't changed", () => MultiplayerClient.ServerAPIRoom?.Playlist[0].Beatmap == firstBeatmap); + AddUntilStep("second playlist item changed", () => MultiplayerClient.ClientAPIRoom?.Playlist[1].Beatmap != firstBeatmap); + } + + [Test] + [FlakyTest] // See above public void TestAddItemsAsHost() { addItem(() => OtherBeatmap); From f63de55a20a92f2669d6faae73cc5716c273a72d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 16 Jan 2023 22:34:29 +0300 Subject: [PATCH 125/376] Mark ready-button-pressing multiplayer tests with `FlakyTest` attribute --- .../Multiplayer/TestSceneMultiplayer.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 5033347b15..d747d23229 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -377,6 +377,17 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] + /* + * On a slight investigation, this is occurring due to the ready button + * not receiving the click input generated by the manual input manager. + * + * TearDown : System.TimeoutException : "wait for ready button to be enabled" 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 TestUserSetToIdleWhenBeatmapDeleted() { createRoom(() => new Room @@ -398,6 +409,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestPlayStartsWithCorrectBeatmapWhileAtSongSelect() { PlaylistItem? item = null; @@ -438,6 +450,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestPlayStartsWithCorrectRulesetWhileAtSongSelect() { PlaylistItem? item = null; @@ -478,6 +491,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestPlayStartsWithCorrectModsWhileAtSongSelect() { PlaylistItem? item = null; @@ -651,6 +665,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestGameplayFlow() { createRoom(() => new Room @@ -678,6 +693,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestGameplayExitFlow() { Bindable? holdDelay = null; @@ -715,6 +731,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestGameplayDoesntStartWithNonLoadedUser() { createRoom(() => new Room @@ -796,6 +813,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestSpectatingStateResetOnBackButtonDuringGameplay() { createRoom(() => new Room @@ -831,6 +849,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestSpectatingStateNotResetOnBackButtonOutsideOfGameplay() { createRoom(() => new Room @@ -869,6 +888,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestItemAddedByOtherUserDuringGameplay() { createRoom(() => new Room @@ -899,6 +919,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestItemAddedAndDeletedByOtherUserDuringGameplay() { createRoom(() => new Room From 0ec608ec5d67dc341ea768ac7e3460cacbd96937 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 16 Jan 2023 22:46:57 +0300 Subject: [PATCH 126/376] Select button using its index in test --- .../Visual/Navigation/TestSceneSkinEditorNavigation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs index e0b61794e4..3b49161dd6 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs @@ -219,7 +219,7 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("Click gameplay scene button", () => { - InputManager.MoveMouseTo(skinEditor.ChildrenOfType().First(b => b.Text == "Gameplay")); + InputManager.MoveMouseTo(skinEditor.ChildrenOfType().Skip(1).First()); InputManager.Click(MouseButton.Left); }); From 133b9b79d768c41711429ff8c329729577c05dcf Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 16 Jan 2023 22:52:17 +0300 Subject: [PATCH 127/376] Do not touch "currently editing" line --- osu.Game/Localisation/SkinEditorStrings.cs | 5 ----- osu.Game/Skinning/Editor/SkinEditor.cs | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/osu.Game/Localisation/SkinEditorStrings.cs b/osu.Game/Localisation/SkinEditorStrings.cs index 605b7d6a9d..b2e5f3aeb6 100644 --- a/osu.Game/Localisation/SkinEditorStrings.cs +++ b/osu.Game/Localisation/SkinEditorStrings.cs @@ -14,11 +14,6 @@ namespace osu.Game.Localisation /// public static LocalisableString SkinEditor => new TranslatableString(getKey(@"skin_editor"), @"Skin editor"); - /// - /// "Currently editing" - /// - public static LocalisableString CurrentlyEditing => new TranslatableString(getKey(@"currently_editing"), @"Currently editing"); - /// /// "Components" /// diff --git a/osu.Game/Skinning/Editor/SkinEditor.cs b/osu.Game/Skinning/Editor/SkinEditor.cs index 74391e5269..98b4e960dd 100644 --- a/osu.Game/Skinning/Editor/SkinEditor.cs +++ b/osu.Game/Skinning/Editor/SkinEditor.cs @@ -254,13 +254,13 @@ namespace osu.Game.Skinning.Editor headerText.AddParagraph(SkinEditorStrings.SkinEditor, cp => cp.Font = OsuFont.Default.With(size: 16)); headerText.NewParagraph(); - headerText.AddText(SkinEditorStrings.CurrentlyEditing, cp => + headerText.AddText("Currently editing ", cp => { cp.Font = OsuFont.Default.With(size: 12); cp.Colour = colours.Yellow; }); - headerText.AddText($" {currentSkin.Value.SkinInfo}", cp => + headerText.AddText($"{currentSkin.Value.SkinInfo}", cp => { cp.Font = OsuFont.Default.With(size: 12, weight: FontWeight.Bold); cp.Colour = colours.Yellow; From 6207a96a29f93733fbd1569d26f0ce02b78ae8f5 Mon Sep 17 00:00:00 2001 From: StanR Date: Mon, 16 Jan 2023 23:24:09 +0300 Subject: [PATCH 128/376] Refactor `LevelBadge` to use `LevelInfo` --- .../Profile/Header/CentreHeaderContainer.cs | 15 ++++++++++++--- .../Profile/Header/Components/LevelBadge.cs | 10 +++++----- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs index 7721342ba8..fbd8f1e0c6 100644 --- a/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs @@ -6,6 +6,7 @@ using osu.Framework.Bindables; 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; @@ -15,6 +16,8 @@ namespace osu.Game.Overlays.Profile.Header { public readonly Bindable User = new Bindable(); + private LevelBadge levelBadge = null!; + public CentreHeaderContainer() { Height = 60; @@ -62,12 +65,11 @@ namespace osu.Game.Overlays.Profile.Header Margin = new MarginPadding { Right = UserProfileOverlay.CONTENT_X_MARGIN }, Children = new Drawable[] { - new LevelBadge + levelBadge = new LevelBadge { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, - Size = new Vector2(40), - User = { BindTarget = User } + Size = new Vector2(40) }, new Container { @@ -85,6 +87,13 @@ namespace osu.Game.Overlays.Profile.Header } } }; + + User.BindValueChanged(user => updateDisplay(user.NewValue?.User)); + } + + private void updateDisplay(APIUser? user) + { + levelBadge.LevelInfo.Value = user?.Statistics?.Level; } } } diff --git a/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs b/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs index 78c5231736..a0c17ccf93 100644 --- a/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs @@ -11,14 +11,14 @@ using osu.Framework.Graphics.Textures; using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Online.API.Requests.Responses; using osu.Game.Resources.Localisation.Web; +using osu.Game.Users; namespace osu.Game.Overlays.Profile.Header.Components { public partial class LevelBadge : CompositeDrawable, IHasTooltip { - public readonly Bindable User = new Bindable(); + public readonly Bindable LevelInfo = new Bindable(); public LocalisableString TooltipText { get; private set; } @@ -48,12 +48,12 @@ namespace osu.Game.Overlays.Profile.Header.Components } }; - User.BindValueChanged(user => updateLevel(user.NewValue?.User)); + LevelInfo.BindValueChanged(user => updateLevel(user.NewValue)); } - private void updateLevel(APIUser? user) + private void updateLevel(UserStatistics.LevelInfo? levelInfo) { - string level = user?.Statistics?.Level.Current.ToString() ?? "0"; + string level = levelInfo?.Current.ToString() ?? "0"; levelText.Text = level; TooltipText = UsersStrings.ShowStatsLevel(level); } From c5d09c0e2c82ff4ae5c7259d6459994972ff3ca2 Mon Sep 17 00:00:00 2001 From: StanR Date: Mon, 16 Jan 2023 23:36:50 +0300 Subject: [PATCH 129/376] Rename variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs b/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs index a0c17ccf93..251cd1bae5 100644 --- a/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs @@ -48,7 +48,7 @@ namespace osu.Game.Overlays.Profile.Header.Components } }; - LevelInfo.BindValueChanged(user => updateLevel(user.NewValue)); + LevelInfo.BindValueChanged(level => updateLevel(level.NewValue)); } private void updateLevel(UserStatistics.LevelInfo? levelInfo) From 3f75506552e9285534cfa47b69aa81cb41633df0 Mon Sep 17 00:00:00 2001 From: StanR Date: Mon, 16 Jan 2023 23:42:07 +0300 Subject: [PATCH 130/376] Move binding to `LoadComplete` --- osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs b/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs index 251cd1bae5..b75ffcaf98 100644 --- a/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs @@ -47,8 +47,11 @@ namespace osu.Game.Overlays.Profile.Header.Components Font = OsuFont.GetFont(size: 20) } }; + } - LevelInfo.BindValueChanged(level => updateLevel(level.NewValue)); + protected override void LoadComplete() + { + LevelInfo.BindValueChanged(level => updateLevel(level.NewValue), true); } private void updateLevel(UserStatistics.LevelInfo? levelInfo) From f79037cefb206f9e57a3dd450d51ec6f7af0c343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 16 Jan 2023 21:47:31 +0100 Subject: [PATCH 131/376] Move to `LoadComplete()` better --- osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs | 7 ++++++- osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs index fbd8f1e0c6..0dab4d582d 100644 --- a/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs @@ -87,8 +87,13 @@ namespace osu.Game.Overlays.Profile.Header } } }; + } - User.BindValueChanged(user => updateDisplay(user.NewValue?.User)); + protected override void LoadComplete() + { + base.LoadComplete(); + + User.BindValueChanged(user => updateDisplay(user.NewValue?.User), true); } private void updateDisplay(APIUser? user) diff --git a/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs b/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs index b75ffcaf98..00bb8cbc75 100644 --- a/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs @@ -51,6 +51,8 @@ namespace osu.Game.Overlays.Profile.Header.Components protected override void LoadComplete() { + base.LoadComplete(); + LevelInfo.BindValueChanged(level => updateLevel(level.NewValue), true); } From 4cf448ec11898985fc56ea2f1178ef765aa412eb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 11:51:17 +0900 Subject: [PATCH 132/376] Use `ToString()` for test instead of linq skip --- .../Visual/Navigation/TestSceneSkinEditorNavigation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs index 3b49161dd6..845cfdd6df 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs @@ -219,7 +219,7 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("Click gameplay scene button", () => { - InputManager.MoveMouseTo(skinEditor.ChildrenOfType().Skip(1).First()); + InputManager.MoveMouseTo(skinEditor.ChildrenOfType().First(b => b.Text.ToString() == "Gameplay")); InputManager.Click(MouseButton.Left); }); From a02556d2fa93e7ca6242ba614af42ab37cc05a53 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 14:43:22 +0900 Subject: [PATCH 133/376] Move hover logic to `SettingsToolboxGroup` to avoid expanded state clash --- osu.Game/Overlays/SettingsToolboxGroup.cs | 4 +++- .../Play/PlayerSettings/PlayerSettingsGroup.cs | 18 ------------------ 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/osu.Game/Overlays/SettingsToolboxGroup.cs b/osu.Game/Overlays/SettingsToolboxGroup.cs index 86964e7ed4..c0948c1eab 100644 --- a/osu.Game/Overlays/SettingsToolboxGroup.cs +++ b/osu.Game/Overlays/SettingsToolboxGroup.cs @@ -135,12 +135,14 @@ namespace osu.Game.Overlays protected override bool OnHover(HoverEvent e) { updateFadeState(); + updateExpandedState(true); return false; } protected override void OnHoverLost(HoverLostEvent e) { updateFadeState(); + updateExpandedState(true); base.OnHoverLost(e); } @@ -168,7 +170,7 @@ namespace osu.Game.Overlays // potentially continuing to get processed while content has changed to autosize. content.ClearTransforms(); - if (Expanded.Value) + if (Expanded.Value || IsHovered) { content.AutoSizeAxes = Axes.Y; content.AutoSizeDuration = animate ? transition_duration : 0; diff --git a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs index ea4d983343..838106e198 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.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.Input.Events; using osu.Game.Overlays; @@ -15,28 +13,12 @@ namespace osu.Game.Screens.Play.PlayerSettings { } - private bool expandedByDefault = true; - protected override bool OnHover(HoverEvent e) { - if (IsHovered && !Expanded.Value) - { - Expanded.Value = true; - expandedByDefault = false; - } - base.OnHover(e); // Importantly, return true to correctly take focus away from PlayerLoader. return true; } - - protected override void OnHoverLost(HoverLostEvent e) - { - if (!expandedByDefault) - Expanded.Value = false; - - base.OnHoverLost(e); - } } } From c6d33df147809ec02b3525371c1aa0db1df68ca0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 14:51:45 +0900 Subject: [PATCH 134/376] Only track `TouchSource` for now --- osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs index 38dbde99b9..c5fc464839 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs @@ -54,7 +54,7 @@ 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 = !mouseDisabled.Value && trackedTouches.All(t => t.Action != action); - trackedTouches.Add(new TrackedTouch(e.Touch, shouldResultInAction ? action : null)); + trackedTouches.Add(new TrackedTouch(e.Touch.Source, shouldResultInAction ? action : null)); // Important to update position before triggering the pressed action. handleTouchMovement(e); @@ -68,7 +68,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 != trackedTouches.Last().Touch) + if (touchEvent.Touch.Source != trackedTouches.Last().Source) return; new MousePositionAbsoluteInput { Position = touchEvent.ScreenSpaceTouch.Position }.Apply(osuInputManager.CurrentState, osuInputManager); @@ -76,7 +76,7 @@ namespace osu.Game.Rulesets.Osu.UI protected override void OnTouchUp(TouchUpEvent e) { - var tracked = trackedTouches.First(t => t.Touch.Source == e.Touch.Source); + var tracked = trackedTouches.First(t => t.Source == e.Touch.Source); if (tracked.Action is OsuAction action) osuInputManager.KeyBindingContainer.TriggerReleased(action); @@ -88,13 +88,13 @@ namespace osu.Game.Rulesets.Osu.UI private class TrackedTouch { - public readonly Touch Touch; + public readonly TouchSource Source; public readonly OsuAction? Action; - public TrackedTouch(Touch touch, OsuAction? action) + public TrackedTouch(TouchSource source, OsuAction? action) { - Touch = touch; + Source = source; Action = action; } } From 9b5d6b391bfc70f3d290aea7bceaaf9fc5cb5876 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 14:52:15 +0900 Subject: [PATCH 135/376] Remove nullability allowance from `BackgroundDependencyLoader` --- osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs index c5fc464839..34a303c098 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.UI osuInputManager = inputManager; } - [BackgroundDependencyLoader(true)] + [BackgroundDependencyLoader] private void load(OsuConfigManager config) { mouseDisabled = config.GetBindable(OsuSetting.MouseDisableButtons); From 34120b61317364e26e88db21b47fcfd418bfd7da Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 14:52:45 +0900 Subject: [PATCH 136/376] Use linq `Single` instead of `First` for guaranteed singular match --- osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs index 34a303c098..6bc1dfd280 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs @@ -76,7 +76,7 @@ namespace osu.Game.Rulesets.Osu.UI protected override void OnTouchUp(TouchUpEvent e) { - var tracked = trackedTouches.First(t => t.Source == e.Touch.Source); + var tracked = trackedTouches.Single(t => t.Source == e.Touch.Source); if (tracked.Action is OsuAction action) osuInputManager.KeyBindingContainer.TriggerReleased(action); From 45b34f5306d70355077a27ccc83816891f15a919 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 14:53:24 +0900 Subject: [PATCH 137/376] Remove pointless xmldoc --- osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs index 6bc1dfd280..e1759da0da 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs @@ -15,17 +15,14 @@ namespace osu.Game.Rulesets.Osu.UI { public partial class OsuTouchInputMapper : Drawable { - /// - /// This is our parent . - /// - private readonly OsuInputManager osuInputManager; - /// /// All the active s and the that it triggered (if any). /// Ordered from oldest to newest touch chronologically. /// private readonly List trackedTouches = new List(); + private readonly OsuInputManager osuInputManager; + private Bindable mouseDisabled = null!; public OsuTouchInputMapper(OsuInputManager inputManager) From 3b95691d53fd8bfb4bc16954d628ae59b4da3371 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 14:54:52 +0900 Subject: [PATCH 138/376] Add note about mouse button disable tracking --- osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs index e1759da0da..0e8dba3ab0 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs @@ -33,6 +33,8 @@ namespace osu.Game.Rulesets.Osu.UI [BackgroundDependencyLoader] private void load(OsuConfigManager config) { + // The mouse button disable setting affects touch. It's a bit weird. + // This is mostly just doing the same as what is done in RulesetInputManager to match behaviour. mouseDisabled = config.GetBindable(OsuSetting.MouseDisableButtons); } From f387a6af57844dc3b022e167a549f12e07263263 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 14:56:07 +0900 Subject: [PATCH 139/376] Apply review feedback to touch test scene --- osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs index 5452405bf0..870a03b118 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs @@ -297,7 +297,7 @@ namespace osu.Game.Rulesets.Osu.Tests public partial class TouchVisualiser : CompositeDrawable { - private readonly Drawable?[] drawableTouches = new Drawable?[10]; + private readonly Drawable?[] drawableTouches = new Drawable?[TouchState.MAX_TOUCH_COUNT]; public TouchVisualiser() { @@ -341,6 +341,9 @@ namespace osu.Game.Rulesets.Osu.Tests protected override void OnTouchUp(TouchUpEvent e) { var circle = drawableTouches[(int)e.Touch.Source]; + + Debug.Assert(circle != null); + circle.FadeOut(200, Easing.OutQuint).Expire(); drawableTouches[(int)e.Touch.Source] = null; } From 490f539c43d104ce4bb0efd6b4727b35c2aab3cf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 15:07:03 +0900 Subject: [PATCH 140/376] Add failing test coverage of relax/autopilot scenarios --- .../TestSceneTouchInput.cs | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs index 870a03b118..10d0143351 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneTouchInput.cs @@ -122,7 +122,38 @@ namespace osu.Game.Rulesets.Osu.Tests } [Test] - public void TestSimpleInputButtonsDisabled() + public void TestMovementWhileDisallowed() + { + // aka "autopilot" mod + + AddStep("Disallow gameplay cursor movement", () => osuInputManager.AllowUserCursorMovement = false); + + Vector2? positionBefore = null; + + AddStep("Store cursor position", () => positionBefore = osuInputManager.CurrentState.Mouse.Position); + beginTouch(TouchSource.Touch1); + + assertKeyCounter(1, 0); + checkPressed(OsuAction.LeftButton); + AddAssert("Cursor position unchanged", () => osuInputManager.CurrentState.Mouse.Position, () => Is.EqualTo(positionBefore)); + } + + [Test] + public void TestActionWhileDisallowed() + { + // aka "relax" mod + + AddStep("Disallow gameplay actions", () => osuInputManager.AllowGameplayInputs = false); + + beginTouch(TouchSource.Touch1); + + assertKeyCounter(0, 0); + checkNotPressed(OsuAction.LeftButton); + checkPosition(TouchSource.Touch1); + } + + [Test] + public void TestInputWhileMouseButtonsDisabled() { AddStep("Disable mouse buttons", () => config.SetValue(OsuSetting.MouseDisableButtons, true)); From 24a626a9cdc2b4fc17b81badf297f1aacf692d34 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 15:01:01 +0900 Subject: [PATCH 141/376] Fix incorrect touch handling in autopilot and relax mods --- osu.Game.Rulesets.Osu/OsuInputManager.cs | 1 + osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/OsuInputManager.cs b/osu.Game.Rulesets.Osu/OsuInputManager.cs index 28b4f70c10..6f69fbef43 100644 --- a/osu.Game.Rulesets.Osu/OsuInputManager.cs +++ b/osu.Game.Rulesets.Osu/OsuInputManager.cs @@ -29,6 +29,7 @@ namespace osu.Game.Rulesets.Osu /// public bool AllowGameplayInputs { + get => ((OsuKeyBindingContainer)KeyBindingContainer).AllowGameplayInputs; set => ((OsuKeyBindingContainer)KeyBindingContainer).AllowGameplayInputs = value; } diff --git a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs index 0e8dba3ab0..c75e179443 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs @@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Osu.UI : OsuAction.LeftButton; // Ignore any taps which trigger an action which is already handled. But track them for potential positional input in the future. - bool shouldResultInAction = !mouseDisabled.Value && trackedTouches.All(t => t.Action != action); + bool shouldResultInAction = osuInputManager.AllowGameplayInputs && !mouseDisabled.Value && trackedTouches.All(t => t.Action != action); trackedTouches.Add(new TrackedTouch(e.Touch.Source, shouldResultInAction ? action : null)); @@ -70,6 +70,9 @@ namespace osu.Game.Rulesets.Osu.UI if (touchEvent.Touch.Source != trackedTouches.Last().Source) return; + if (!osuInputManager.AllowUserCursorMovement) + return; + new MousePositionAbsoluteInput { Position = touchEvent.ScreenSpaceTouch.Position }.Apply(osuInputManager.CurrentState, osuInputManager); } From ef354938646837725471a384172021f95a8ed51b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 15:27:19 +0900 Subject: [PATCH 142/376] Avoid need for weird null check by reordering initialisation process --- osu.Game/Screens/Select/SongSelect.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index d4d75d0ad6..64deb59026 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -127,9 +127,6 @@ namespace osu.Game.Screens.Select [BackgroundDependencyLoader(true)] private void load(AudioManager audio, OsuColour colours, ManageCollectionsDialog? manageCollectionsDialog, DifficultyRecommender? recommender) { - // initial value transfer is required for FilterControl (it uses our re-cached bindables in its async load for the initial filter). - transferRulesetValue(); - LoadComponentAsync(Carousel = new BeatmapCarousel { AllowSelection = false, // delay any selection until our bindables are ready to make a good choice. @@ -143,6 +140,9 @@ namespace osu.Game.Screens.Select GetRecommendedBeatmap = s => recommender?.GetRecommendedBeatmap(s), }, c => carouselContainer.Child = c); + // initial value transfer is required for FilterControl (it uses our re-cached bindables in its async load for the initial filter). + transferRulesetValue(); + AddRangeInternal(new Drawable[] { new ResetScrollContainer(() => Carousel.ScrollToSelected()) @@ -860,9 +860,6 @@ namespace osu.Game.Screens.Select Logger.Log($"decoupled ruleset transferred (\"{decoupledRuleset.Value}\" -> \"{Ruleset.Value}\")"); rulesetNoDebounce = decoupledRuleset.Value = Ruleset.Value; - // We want to check for null since this method gets called before the loading of the carousel. - if (Carousel.IsNull()) return true; - // if we have a pending filter operation, we want to run it now. // it could change selection (ie. if the ruleset has been changed). Carousel.FlushPendingFilterOperations(); From 08c570849f15c77e2f8fc7ab6800c5db742f5155 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Mon, 16 Jan 2023 23:24:47 -0800 Subject: [PATCH 143/376] Simplify container logic --- osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs b/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs index 8e0ee896a5..a5e0bddc6b 100644 --- a/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs +++ b/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs @@ -46,8 +46,6 @@ namespace osu.Game.Tests.Visual { var mainContent = content = new Container { RelativeSizeAxes = Axes.Both }; - var inputContainer = new Container { RelativeSizeAxes = Axes.Both }; - if (DisplayCursorForManualInput) { var cursorDisplay = new GlobalCursorDisplay { RelativeSizeAxes = Axes.Both }; @@ -57,12 +55,11 @@ namespace osu.Game.Tests.Visual RelativeSizeAxes = Axes.Both, }); - inputContainer.Add(cursorDisplay); - mainContent = inputContainer; + mainContent.Add(cursorDisplay); } if (CreateNestedActionContainer) - inputContainer.Add(new GlobalActionContainer(null)); + mainContent.Add(new GlobalActionContainer(null)); base.Content.AddRange(new Drawable[] { From 8f7cb18217187084ccdecebe9328cbbcc98f3324 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Mon, 16 Jan 2023 23:36:28 -0800 Subject: [PATCH 144/376] Use `TriggerClick()` instead of calling `BackButton` action for pause gameplay --- osu.Game/Screens/Play/PauseOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/PauseOverlay.cs b/osu.Game/Screens/Play/PauseOverlay.cs index db2b87dae6..dc4c4fdc5a 100644 --- a/osu.Game/Screens/Play/PauseOverlay.cs +++ b/osu.Game/Screens/Play/PauseOverlay.cs @@ -64,7 +64,7 @@ namespace osu.Game.Screens.Play switch (e.Action) { case GlobalAction.PauseGameplay: - BackAction.Invoke(); + InternalButtons.Children.First().TriggerClick(); return true; } From 92fc439f8240d9bf2c384711dafa2c90c402b671 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 16:35:45 +0900 Subject: [PATCH 145/376] Add test coverage of carousel sort expectations This covers the fail case of removing and adding items (see https://github.com/ppy/osu/issues/21926) but also covers the proposed forward implementation, which now considers `DateAdded` and `OnlineID`. --- .../SongSelect/TestSceneBeatmapCarousel.cs | 100 +++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index ea9508ecff..e658d87497 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -580,7 +580,44 @@ namespace osu.Game.Tests.Visual.SongSelect /// Ensures stability is maintained on different sort modes for items with equal properties. /// [Test] - public void TestSortingStability() + public void TestSortingStabilityDateAdded() + { + var sets = new List(); + + AddStep("Populuate beatmap sets", () => + { + sets.Clear(); + + for (int i = 0; i < 10; i++) + { + var set = TestResources.CreateTestBeatmapSetInfo(); + + set.DateAdded = DateTimeOffset.FromUnixTimeSeconds(i); + + // only need to set the first as they are a shared reference. + var beatmap = set.Beatmaps.First(); + + beatmap.Metadata.Artist = "a"; + beatmap.Metadata.Title = "b"; + + sets.Add(set); + } + }); + + loadBeatmaps(sets); + + AddStep("Sort by title", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Title }, false)); + AddAssert("Items remain in descending added order", () => carousel.BeatmapSets.Select(s => s.DateAdded), () => Is.Ordered.Descending); + + AddStep("Sort by artist", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Artist }, false)); + AddAssert("Items remain in descending added order", () => carousel.BeatmapSets.Select(s => s.DateAdded), () => Is.Ordered.Descending); + } + + /// + /// Ensures stability is maintained on different sort modes for items with equal properties. + /// + [Test] + public void TestSortingStabilityOnlineID() { var sets = new List(); int idOffset = 0; @@ -599,6 +636,9 @@ namespace osu.Game.Tests.Visual.SongSelect beatmap.Metadata.Artist = $"artist {i / 2}"; beatmap.Metadata.Title = $"title {9 - i}"; + // testing the case where DateAdded happens to equal (quite rare). + set.DateAdded = DateTimeOffset.UnixEpoch; + sets.Add(set); } @@ -617,6 +657,58 @@ namespace osu.Game.Tests.Visual.SongSelect AddAssert("Items reset to original order", () => carousel.BeatmapSets.Select((set, index) => set.OnlineID == idOffset + index).All(b => b)); } + /// + /// Ensures stability is maintained on different sort modes while a new item is added to the carousel. + /// + [Test] + public void TestSortingStabilityWithRemovedAndReaddedItem() + { + List sets = new List(); + int idOffset = 0; + + AddStep("Populuate beatmap sets", () => + { + sets.Clear(); + + for (int i = 0; i < 3; i++) + { + var set = TestResources.CreateTestBeatmapSetInfo(3); + + // only need to set the first as they are a shared reference. + var beatmap = set.Beatmaps.First(); + + beatmap.Metadata.Artist = "same artist"; + beatmap.Metadata.Title = "same title"; + + // testing the case where DateAdded happens to equal (quite rare). + set.DateAdded = DateTimeOffset.UnixEpoch; + + sets.Add(set); + } + + idOffset = sets.First().OnlineID; + }); + + loadBeatmaps(sets); + + AddStep("Sort by artist", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Artist }, false)); + assertOriginalOrderMaintained(); + + AddStep("Remove item", () => carousel.RemoveBeatmapSet(sets[1])); + AddStep("Re-add item", () => carousel.UpdateBeatmapSet(sets[1])); + + assertOriginalOrderMaintained(); + + AddStep("Sort by title", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Title }, false)); + assertOriginalOrderMaintained(); + + void assertOriginalOrderMaintained() + { + AddAssert("Items remain in original order", + () => carousel.BeatmapSets.Select(s => s.OnlineID), () => Is.EqualTo(carousel.BeatmapSets.Select((set, index) => idOffset + index))); + } + } + /// /// Ensures stability is maintained on different sort modes while a new item is added to the carousel. /// @@ -640,6 +732,9 @@ namespace osu.Game.Tests.Visual.SongSelect beatmap.Metadata.Artist = "same artist"; beatmap.Metadata.Title = "same title"; + // testing the case where DateAdded happens to equal (quite rare). + set.DateAdded = DateTimeOffset.UnixEpoch; + sets.Add(set); } @@ -661,6 +756,9 @@ namespace osu.Game.Tests.Visual.SongSelect beatmap.Metadata.Artist = "same artist"; beatmap.Metadata.Title = "same title"; + // testing the case where DateAdded happens to equal (quite rare). + set.DateAdded = DateTimeOffset.UnixEpoch; + carousel.UpdateBeatmapSet(set); }); From a9ac28b504357becf852dbf863cb121778b5781d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 16:36:47 +0900 Subject: [PATCH 146/376] Add fallback sorts to `CarouselBeatmapSet` to ensure stable sorting --- .../Select/Carousel/CarouselBeatmapSet.cs | 55 ++++++++++++++----- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs index a360ddabc7..7c919d3586 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs @@ -61,50 +61,79 @@ namespace osu.Game.Screens.Select.Carousel if (!(other is CarouselBeatmapSet otherSet)) return base.CompareTo(criteria, other); + int comparison = 0; + switch (criteria.Sort) { default: case SortMode.Artist: - return string.Compare(BeatmapSet.Metadata.Artist, otherSet.BeatmapSet.Metadata.Artist, StringComparison.OrdinalIgnoreCase); + comparison = string.Compare(BeatmapSet.Metadata.Artist, otherSet.BeatmapSet.Metadata.Artist, StringComparison.OrdinalIgnoreCase); + break; case SortMode.Title: - return string.Compare(BeatmapSet.Metadata.Title, otherSet.BeatmapSet.Metadata.Title, StringComparison.OrdinalIgnoreCase); + comparison = string.Compare(BeatmapSet.Metadata.Title, otherSet.BeatmapSet.Metadata.Title, StringComparison.OrdinalIgnoreCase); + break; case SortMode.Author: - return string.Compare(BeatmapSet.Metadata.Author.Username, otherSet.BeatmapSet.Metadata.Author.Username, StringComparison.OrdinalIgnoreCase); + comparison = string.Compare(BeatmapSet.Metadata.Author.Username, otherSet.BeatmapSet.Metadata.Author.Username, StringComparison.OrdinalIgnoreCase); + break; case SortMode.Source: - return string.Compare(BeatmapSet.Metadata.Source, otherSet.BeatmapSet.Metadata.Source, StringComparison.OrdinalIgnoreCase); + comparison = string.Compare(BeatmapSet.Metadata.Source, otherSet.BeatmapSet.Metadata.Source, StringComparison.OrdinalIgnoreCase); + break; case SortMode.DateAdded: - return otherSet.BeatmapSet.DateAdded.CompareTo(BeatmapSet.DateAdded); + comparison = otherSet.BeatmapSet.DateAdded.CompareTo(BeatmapSet.DateAdded); + break; case SortMode.DateRanked: // Beatmaps which have no ranked date should already be filtered away in this mode. if (BeatmapSet.DateRanked == null || otherSet.BeatmapSet.DateRanked == null) - return 0; + break; - return otherSet.BeatmapSet.DateRanked.Value.CompareTo(BeatmapSet.DateRanked.Value); + comparison = otherSet.BeatmapSet.DateRanked.Value.CompareTo(BeatmapSet.DateRanked.Value); + break; case SortMode.LastPlayed: - return -compareUsingAggregateMax(otherSet, b => (b.LastPlayed ?? DateTimeOffset.MinValue).ToUnixTimeSeconds()); + comparison = -compareUsingAggregateMax(otherSet, b => (b.LastPlayed ?? DateTimeOffset.MinValue).ToUnixTimeSeconds()); + break; case SortMode.BPM: - return compareUsingAggregateMax(otherSet, b => b.BPM); + comparison = compareUsingAggregateMax(otherSet, b => b.BPM); + break; case SortMode.Length: - return compareUsingAggregateMax(otherSet, b => b.Length); + comparison = compareUsingAggregateMax(otherSet, b => b.Length); + break; case SortMode.Difficulty: - return compareUsingAggregateMax(otherSet, b => b.StarRating); + comparison = compareUsingAggregateMax(otherSet, b => b.StarRating); + break; case SortMode.DateSubmitted: // Beatmaps which have no submitted date should already be filtered away in this mode. if (BeatmapSet.DateSubmitted == null || otherSet.BeatmapSet.DateSubmitted == null) - return 0; + break; - return otherSet.BeatmapSet.DateSubmitted.Value.CompareTo(BeatmapSet.DateSubmitted.Value); + comparison = otherSet.BeatmapSet.DateSubmitted.Value.CompareTo(BeatmapSet.DateSubmitted.Value); + break; } + + if (comparison != 0) return comparison; + + // If the initial sort could not differentiate, attempt to use DateAdded and OnlineID to order sets in a stable fashion. + // This directionality is a touch arbitrary as while DateAdded puts newer beatmaps first, the OnlineID fallback puts lower IDs first. + // Can potentially be changed in the future if users actually notice / have preference, but keeping it this way matches historical tests. + + comparison = otherSet.BeatmapSet.DateAdded.CompareTo(BeatmapSet.DateAdded); + if (comparison != 0) return comparison; + + comparison = BeatmapSet.OnlineID.CompareTo(otherSet.BeatmapSet.OnlineID); + if (comparison != 0) return comparison; + + // If no online ID is available, fallback to our internal GUID for stability. + // This basically means it's a stable random sort. + return otherSet.BeatmapSet.ID.CompareTo(BeatmapSet.ID); } /// From 23ea77cb74034f2e19071a4758329efc8fad4ba0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 17:03:04 +0900 Subject: [PATCH 147/376] 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 da0eb9b0cbe7ef101063085d244102fe7db389b4 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 17 Jan 2023 00:34:52 -0800 Subject: [PATCH 148/376] Simplify `TriggerClick`s in gameplay menu overlays --- osu.Game/Screens/Play/GameplayMenuOverlay.cs | 2 +- osu.Game/Screens/Play/PauseOverlay.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/GameplayMenuOverlay.cs b/osu.Game/Screens/Play/GameplayMenuOverlay.cs index 13f32d3b6a..81146a4ea6 100644 --- a/osu.Game/Screens/Play/GameplayMenuOverlay.cs +++ b/osu.Game/Screens/Play/GameplayMenuOverlay.cs @@ -44,7 +44,7 @@ namespace osu.Game.Screens.Play /// /// Action that is invoked when is triggered. /// - protected virtual Action BackAction => () => InternalButtons.Children.LastOrDefault()?.TriggerClick(); + protected virtual Action BackAction => () => InternalButtons.LastOrDefault()?.TriggerClick(); /// /// Action that is invoked when is triggered. diff --git a/osu.Game/Screens/Play/PauseOverlay.cs b/osu.Game/Screens/Play/PauseOverlay.cs index dc4c4fdc5a..d9c60519ad 100644 --- a/osu.Game/Screens/Play/PauseOverlay.cs +++ b/osu.Game/Screens/Play/PauseOverlay.cs @@ -28,7 +28,7 @@ namespace osu.Game.Screens.Play private SkinnableSound pauseLoop; - protected override Action BackAction => () => InternalButtons.Children.First().TriggerClick(); + protected override Action BackAction => () => InternalButtons.First().TriggerClick(); [BackgroundDependencyLoader] private void load(OsuColour colours) @@ -64,7 +64,7 @@ namespace osu.Game.Screens.Play switch (e.Action) { case GlobalAction.PauseGameplay: - InternalButtons.Children.First().TriggerClick(); + InternalButtons.First().TriggerClick(); return true; } From b62b5714e89199159341757688bd5abe01b008ea Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 18:07:11 +0900 Subject: [PATCH 149/376] Fix `TierColours` assignment --- osu.Game/Graphics/UserInterface/SegmentedGraph.cs | 9 +++------ osu.Game/Screens/Play/HUD/ArgonSongProgressGraph.cs | 8 +++++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/SegmentedGraph.cs b/osu.Game/Graphics/UserInterface/SegmentedGraph.cs index 8ccba710b8..dab7ec0559 100644 --- a/osu.Game/Graphics/UserInterface/SegmentedGraph.cs +++ b/osu.Game/Graphics/UserInterface/SegmentedGraph.cs @@ -48,17 +48,14 @@ namespace osu.Game.Graphics.UserInterface } } - private Colour4[] tierColours; + private IReadOnlyList tierColours; - public Colour4[] TierColours + public IReadOnlyList TierColours { get => tierColours; set { - if (value.Length == 0 || value == tierColours) - return; - - tierCount = value.Length; + tierCount = value.Count; tierColours = value; graphNeedsUpdate = true; diff --git a/osu.Game/Screens/Play/HUD/ArgonSongProgressGraph.cs b/osu.Game/Screens/Play/HUD/ArgonSongProgressGraph.cs index 2c82faf7b2..577d79886c 100644 --- a/osu.Game/Screens/Play/HUD/ArgonSongProgressGraph.cs +++ b/osu.Game/Screens/Play/HUD/ArgonSongProgressGraph.cs @@ -53,10 +53,12 @@ namespace osu.Game.Screens.Play.HUD public ArgonSongProgressGraph() : base(5) { + var colours = new List(); + for (int i = 0; i < 5; i++) - { - TierColours[i] = Colour4.White.Opacity(1 / 5f * 0.85f); - } + colours.Add(Colour4.White.Opacity(1 / 5f * 0.85f)); + + TierColours = colours; } } } From 0a7d6948ca5f6947e5f1f49cf464672bb33c54d3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 18:16:46 +0900 Subject: [PATCH 150/376] Nest model class --- .../HUD/JudgementCounter/JudgementCounter.cs | 4 ++-- .../JudgementCounter/JudgementCounterDisplay.cs | 2 +- .../JudgementCounter/JudgementCounterInfo.cs | 15 --------------- .../Play/HUD/JudgementCounter/JudgementTally.cs | 17 ++++++++++++++--- 4 files changed, 17 insertions(+), 21 deletions(-) delete mode 100644 osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterInfo.cs diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs index ea6e9997e3..635b9220f4 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs @@ -18,9 +18,9 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter public BindableBool ShowName = new BindableBool(); public Bindable Direction = new Bindable(); - public readonly JudgementCounterInfo Result; + public readonly JudgementTally.JudgementCount Result; - public JudgementCounter(JudgementCounterInfo result) => Result = result; + public JudgementCounter(JudgementTally.JudgementCount result) => Result = result; public OsuSpriteText ResultName = null!; private FillFlowContainer flowContainer = null!; diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs index 4e2b2a10cd..7dd28b29b9 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs @@ -124,7 +124,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter All } - private JudgementCounter createCounter(JudgementCounterInfo info) + private JudgementCounter createCounter(JudgementTally.JudgementCount info) { JudgementCounter counter = new JudgementCounter(info) { diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterInfo.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterInfo.cs deleted file mode 100644 index 0237981db1..0000000000 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterInfo.cs +++ /dev/null @@ -1,15 +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.Bindables; -using osu.Game.Rulesets.Scoring; - -namespace osu.Game.Screens.Play.HUD.JudgementCounter -{ - public struct JudgementCounterInfo - { - public HitResult Type { get; set; } - - public BindableInt ResultCount { get; set; } - } -} diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs index d8eac309aa..e9e3fde92a 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementTally.cs @@ -12,19 +12,23 @@ using osu.Game.Rulesets.Scoring; namespace osu.Game.Screens.Play.HUD.JudgementCounter { + /// + /// Keeps track of judgements for a current play session, exposing bindable counts which can + /// be used for display purposes. + /// public partial class JudgementTally : CompositeDrawable { [Resolved] private ScoreProcessor scoreProcessor { get; set; } = null!; - public List Results = new List(); + public List Results = new List(); [BackgroundDependencyLoader] private void load(IBindable ruleset) { foreach (var result in ruleset.Value.CreateInstance().GetHitResults()) { - Results.Add(new JudgementCounterInfo + Results.Add(new JudgementCount { Type = result.result, ResultCount = new BindableInt() @@ -42,8 +46,15 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter private void updateCount(JudgementResult judgement, bool revert) { - foreach (JudgementCounterInfo result in Results.Where(result => result.Type == judgement.Type)) + foreach (JudgementCount result in Results.Where(result => result.Type == judgement.Type)) result.ResultCount.Value = revert ? result.ResultCount.Value - 1 : result.ResultCount.Value + 1; } + + public struct JudgementCount + { + public HitResult Type { get; set; } + + public BindableInt ResultCount { get; set; } + } } } From f923dc500937e4628c26a1917db63db296fe239d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 18:21:30 +0900 Subject: [PATCH 151/376] Use framework `Direction` instead of local enum It should be stable enough to use. --- .../Gameplay/TestSceneJudgementCounter.cs | 4 +-- .../JudgementCounterDisplay.cs | 35 ++++++++----------- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs index a8d9f203ae..abd66d85ae 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs @@ -94,8 +94,8 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestChangeFlowDirection() { - AddStep("Set direction vertical", () => counterDisplay.FlowDirection.Value = JudgementCounterDisplay.Flow.Vertical); - AddStep("Set direction horizontal", () => counterDisplay.FlowDirection.Value = JudgementCounterDisplay.Flow.Horizontal); + AddStep("Set direction vertical", () => counterDisplay.FlowDirection.Value = Direction.Vertical); + AddStep("Set direction horizontal", () => counterDisplay.FlowDirection.Value = Direction.Horizontal); } [Test] diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs index 7dd28b29b9..6aa956943b 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs @@ -23,7 +23,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter public Bindable Mode { get; set; } = new Bindable(); [SettingSource("Counter direction")] - public Bindable FlowDirection { get; set; } = new Bindable(); + public Bindable FlowDirection { get; set; } = new Bindable(); [SettingSource("Show judgement names")] public BindableBool ShowName { get; set; } = new BindableBool(true); @@ -42,7 +42,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter AutoSizeAxes = Axes.Both; InternalChild = JudgementContainer = new FillFlowContainer { - Direction = getFlow(FlowDirection.Value), + Direction = getFillDirection(FlowDirection.Value), Spacing = new Vector2(10), AutoSizeAxes = Axes.Both }; @@ -57,11 +57,11 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter FlowDirection.BindValueChanged(direction => { - JudgementContainer.Direction = getFlow(direction.NewValue); + JudgementContainer.Direction = getFillDirection(direction.NewValue); //Can't pass directly due to Enum conversion foreach (var counter in JudgementContainer.Children.OfType()) - counter.Direction.Value = getFlow(direction.NewValue); + counter.Direction.Value = getFillDirection(direction.NewValue); }, true); Mode.BindValueChanged(_ => updateMode(), true); ShowMax.BindValueChanged(value => @@ -95,14 +95,14 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter } } - private FillDirection getFlow(Flow flow) + private FillDirection getFillDirection(Direction flow) { switch (flow) { - case Flow.Horizontal: + case Direction.Horizontal: return FillDirection.Horizontal; - case Flow.Vertical: + case Direction.Vertical: return FillDirection.Vertical; default: @@ -110,20 +110,6 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter } } - //Used to hide default full option in FillDirection - public enum Flow - { - Horizontal, - Vertical - } - - public enum DisplayMode - { - Simple, - Normal, - All - } - private JudgementCounter createCounter(JudgementTally.JudgementCount info) { JudgementCounter counter = new JudgementCounter(info) @@ -133,5 +119,12 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter }; return counter; } + + public enum DisplayMode + { + Simple, + Normal, + All + } } } From 09c7ab3af628d71e9f860cea3dddd1fa281ca3d6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 18:24:55 +0900 Subject: [PATCH 152/376] Rename exposed settings to make more sense --- .../Visual/Gameplay/TestSceneJudgementCounter.cs | 8 ++++---- .../Play/HUD/JudgementCounter/JudgementCounterDisplay.cs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs index abd66d85ae..f387f1e055 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs @@ -101,10 +101,10 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestToggleJudgementNames() { - AddStep("Hide judgement names", () => counterDisplay.ShowName.Value = false); + AddStep("Hide judgement names", () => counterDisplay.ShowJudgementNames.Value = false); AddWaitStep("wait some", 2); AddAssert("Assert hidden", () => counterDisplay.JudgementContainer.Children.OfType().First().ResultName.Alpha == 0); - AddStep("Hide judgement names", () => counterDisplay.ShowName.Value = true); + AddStep("Hide judgement names", () => counterDisplay.ShowJudgementNames.Value = true); AddWaitStep("wait some", 2); AddAssert("Assert shown", () => counterDisplay.JudgementContainer.Children.OfType().First().ResultName.Alpha == 1); } @@ -112,10 +112,10 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestHideMaxValue() { - AddStep("Hide max judgement", () => counterDisplay.ShowMax.Value = false); + AddStep("Hide max judgement", () => counterDisplay.ShowMaxJudgement.Value = false); AddWaitStep("wait some", 2); AddAssert("Check max hidden", () => counterDisplay.JudgementContainer.ChildrenOfType().First().Alpha == 0); - AddStep("Show max judgement", () => counterDisplay.ShowMax.Value = true); + AddStep("Show max judgement", () => counterDisplay.ShowMaxJudgement.Value = true); } [Test] diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs index 6aa956943b..f4a732e68e 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs @@ -26,10 +26,10 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter public Bindable FlowDirection { get; set; } = new Bindable(); [SettingSource("Show judgement names")] - public BindableBool ShowName { get; set; } = new BindableBool(true); + public BindableBool ShowJudgementNames { get; set; } = new BindableBool(true); [SettingSource("Show max judgement")] - public BindableBool ShowMax { get; set; } = new BindableBool(true); + public BindableBool ShowMaxJudgement { get; set; } = new BindableBool(true); [Resolved] private JudgementTally tally { get; set; } = null!; @@ -64,7 +64,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter counter.Direction.Value = getFillDirection(direction.NewValue); }, true); Mode.BindValueChanged(_ => updateMode(), true); - ShowMax.BindValueChanged(value => + ShowMaxJudgement.BindValueChanged(value => { var firstChild = JudgementContainer.Children.FirstOrDefault(); firstChild.FadeTo(value.NewValue ? 1 : 0, TRANSFORM_DURATION, Easing.OutQuint); @@ -115,7 +115,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter JudgementCounter counter = new JudgementCounter(info) { State = { Value = Visibility.Visible }, - ShowName = { BindTarget = ShowName } + ShowName = { BindTarget = ShowJudgementNames } }; return counter; } From 35ad66eef94e6a9ec9202b29772e4643e1bf895a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 18:27:33 +0900 Subject: [PATCH 153/376] Give flow container a type to avoid locally casting in every location --- .../Visual/Gameplay/TestSceneJudgementCounter.cs | 8 ++++---- .../JudgementCounter/JudgementCounterDisplay.cs | 15 ++++++--------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs index f387f1e055..0a501c55c7 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs @@ -103,10 +103,10 @@ namespace osu.Game.Tests.Visual.Gameplay { AddStep("Hide judgement names", () => counterDisplay.ShowJudgementNames.Value = false); AddWaitStep("wait some", 2); - AddAssert("Assert hidden", () => counterDisplay.JudgementContainer.Children.OfType().First().ResultName.Alpha == 0); + AddAssert("Assert hidden", () => counterDisplay.JudgementContainer.Children.First().ResultName.Alpha == 0); AddStep("Hide judgement names", () => counterDisplay.ShowJudgementNames.Value = true); AddWaitStep("wait some", 2); - AddAssert("Assert shown", () => counterDisplay.JudgementContainer.Children.OfType().First().ResultName.Alpha == 1); + AddAssert("Assert shown", () => counterDisplay.JudgementContainer.Children.First().ResultName.Alpha == 1); } [Test] @@ -132,13 +132,13 @@ namespace osu.Game.Tests.Visual.Gameplay private int hiddenCount() { - var num = counterDisplay.JudgementContainer.Children.OfType().First(child => child.Result.Type == HitResult.LargeTickHit); + var num = counterDisplay.JudgementContainer.Children.First(child => child.Result.Type == HitResult.LargeTickHit); return num.Result.ResultCount.Value; } private partial class TestJudgementCounterDisplay : JudgementCounterDisplay { - public new FillFlowContainer JudgementContainer => base.JudgementContainer; + public new FillFlowContainer JudgementContainer => base.JudgementContainer; } } } diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs index f4a732e68e..d3efbc9871 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs @@ -34,13 +34,13 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter [Resolved] private JudgementTally tally { get; set; } = null!; - protected FillFlowContainer JudgementContainer = null!; + protected FillFlowContainer JudgementContainer = null!; [BackgroundDependencyLoader] private void load() { AutoSizeAxes = Axes.Both; - InternalChild = JudgementContainer = new FillFlowContainer + InternalChild = JudgementContainer = new FillFlowContainer { Direction = getFillDirection(FlowDirection.Value), Spacing = new Vector2(10), @@ -60,7 +60,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter JudgementContainer.Direction = getFillDirection(direction.NewValue); //Can't pass directly due to Enum conversion - foreach (var counter in JudgementContainer.Children.OfType()) + foreach (var counter in JudgementContainer.Children) counter.Direction.Value = getFillDirection(direction.NewValue); }, true); Mode.BindValueChanged(_ => updateMode(), true); @@ -73,7 +73,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter private void updateMode() { - foreach (var counter in JudgementContainer.Children.OfType().Where(counter => !counter.Result.Type.IsBasic())) + foreach (var counter in JudgementContainer.Children.Where(counter => !counter.Result.Type.IsBasic())) { switch (Mode.Value) { @@ -110,15 +110,12 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter } } - private JudgementCounter createCounter(JudgementTally.JudgementCount info) - { - JudgementCounter counter = new JudgementCounter(info) + private JudgementCounter createCounter(JudgementTally.JudgementCount info) => + new JudgementCounter(info) { State = { Value = Visibility.Visible }, ShowName = { BindTarget = ShowJudgementNames } }; - return counter; - } public enum DisplayMode { From 181473c5fc9c9c0d784d4ad834ec82a3d242eaca Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 18:28:08 +0900 Subject: [PATCH 154/376] Rename flow to better match its purpose --- .../Visual/Gameplay/TestSceneJudgementCounter.cs | 14 +++++++------- .../JudgementCounter/JudgementCounterDisplay.cs | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs index 0a501c55c7..d104e25df0 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs @@ -103,10 +103,10 @@ namespace osu.Game.Tests.Visual.Gameplay { AddStep("Hide judgement names", () => counterDisplay.ShowJudgementNames.Value = false); AddWaitStep("wait some", 2); - AddAssert("Assert hidden", () => counterDisplay.JudgementContainer.Children.First().ResultName.Alpha == 0); + AddAssert("Assert hidden", () => counterDisplay.CounterFlow.Children.First().ResultName.Alpha == 0); AddStep("Hide judgement names", () => counterDisplay.ShowJudgementNames.Value = true); AddWaitStep("wait some", 2); - AddAssert("Assert shown", () => counterDisplay.JudgementContainer.Children.First().ResultName.Alpha == 1); + AddAssert("Assert shown", () => counterDisplay.CounterFlow.Children.First().ResultName.Alpha == 1); } [Test] @@ -114,7 +114,7 @@ namespace osu.Game.Tests.Visual.Gameplay { AddStep("Hide max judgement", () => counterDisplay.ShowMaxJudgement.Value = false); AddWaitStep("wait some", 2); - AddAssert("Check max hidden", () => counterDisplay.JudgementContainer.ChildrenOfType().First().Alpha == 0); + AddAssert("Check max hidden", () => counterDisplay.CounterFlow.ChildrenOfType().First().Alpha == 0); AddStep("Show max judgement", () => counterDisplay.ShowMaxJudgement.Value = true); } @@ -123,22 +123,22 @@ namespace osu.Game.Tests.Visual.Gameplay { AddStep("Show basic judgements", () => counterDisplay.Mode.Value = JudgementCounterDisplay.DisplayMode.Simple); AddWaitStep("wait some", 2); - AddAssert("Check only basic", () => counterDisplay.JudgementContainer.ChildrenOfType().Last().Alpha == 0); + AddAssert("Check only basic", () => counterDisplay.CounterFlow.ChildrenOfType().Last().Alpha == 0); AddStep("Show normal judgements", () => counterDisplay.Mode.Value = JudgementCounterDisplay.DisplayMode.Normal); AddStep("Show all judgements", () => counterDisplay.Mode.Value = JudgementCounterDisplay.DisplayMode.All); AddWaitStep("wait some", 2); - AddAssert("Check all visible", () => counterDisplay.JudgementContainer.ChildrenOfType().Last().Alpha == 1); + AddAssert("Check all visible", () => counterDisplay.CounterFlow.ChildrenOfType().Last().Alpha == 1); } private int hiddenCount() { - var num = counterDisplay.JudgementContainer.Children.First(child => child.Result.Type == HitResult.LargeTickHit); + var num = counterDisplay.CounterFlow.Children.First(child => child.Result.Type == HitResult.LargeTickHit); return num.Result.ResultCount.Value; } private partial class TestJudgementCounterDisplay : JudgementCounterDisplay { - public new FillFlowContainer JudgementContainer => base.JudgementContainer; + public new FillFlowContainer CounterFlow => base.CounterFlow; } } } diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs index d3efbc9871..a29335ff50 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs @@ -34,13 +34,13 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter [Resolved] private JudgementTally tally { get; set; } = null!; - protected FillFlowContainer JudgementContainer = null!; + protected FillFlowContainer CounterFlow = null!; [BackgroundDependencyLoader] private void load() { AutoSizeAxes = Axes.Both; - InternalChild = JudgementContainer = new FillFlowContainer + InternalChild = CounterFlow = new FillFlowContainer { Direction = getFillDirection(FlowDirection.Value), Spacing = new Vector2(10), @@ -48,7 +48,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter }; foreach (var result in tally.Results) - JudgementContainer.Add(createCounter(result)); + CounterFlow.Add(createCounter(result)); } protected override void LoadComplete() @@ -57,23 +57,23 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter FlowDirection.BindValueChanged(direction => { - JudgementContainer.Direction = getFillDirection(direction.NewValue); + CounterFlow.Direction = getFillDirection(direction.NewValue); //Can't pass directly due to Enum conversion - foreach (var counter in JudgementContainer.Children) + foreach (var counter in CounterFlow.Children) counter.Direction.Value = getFillDirection(direction.NewValue); }, true); Mode.BindValueChanged(_ => updateMode(), true); ShowMaxJudgement.BindValueChanged(value => { - var firstChild = JudgementContainer.Children.FirstOrDefault(); + var firstChild = CounterFlow.Children.FirstOrDefault(); firstChild.FadeTo(value.NewValue ? 1 : 0, TRANSFORM_DURATION, Easing.OutQuint); }, true); } private void updateMode() { - foreach (var counter in JudgementContainer.Children.Where(counter => !counter.Result.Type.IsBasic())) + foreach (var counter in CounterFlow.Children.Where(counter => !counter.Result.Type.IsBasic())) { switch (Mode.Value) { From ca1799376952d97a77e97ce0ca88cd31bbdd2beb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 18:30:50 +0900 Subject: [PATCH 155/376] Don't use `OverlayContainer` (what) --- osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs index 635b9220f4..0630b73376 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs @@ -13,7 +13,7 @@ using osu.Game.Rulesets.Scoring; namespace osu.Game.Screens.Play.HUD.JudgementCounter { - public partial class JudgementCounter : OverlayContainer + public partial class JudgementCounter : VisibilityContainer { public BindableBool ShowName = new BindableBool(); public Bindable Direction = new Bindable(); @@ -30,6 +30,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter private void load(OsuColour colours, IBindable ruleset) { AutoSizeAxes = Axes.Both; + InternalChild = flowContainer = new FillFlowContainer { AutoSizeAxes = Axes.Both, From 448abf897a5824c115d0071a2f15f876e48572a6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 18:31:08 +0900 Subject: [PATCH 156/376] Tidy up direction assignment --- .../Play/HUD/JudgementCounter/JudgementCounterDisplay.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs index a29335ff50..0899870005 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs @@ -57,13 +57,16 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter FlowDirection.BindValueChanged(direction => { - CounterFlow.Direction = getFillDirection(direction.NewValue); + var convertedDirection = getFillDirection(direction.NewValue); + + CounterFlow.Direction = convertedDirection; - //Can't pass directly due to Enum conversion foreach (var counter in CounterFlow.Children) - counter.Direction.Value = getFillDirection(direction.NewValue); + counter.Direction.Value = convertedDirection; }, true); + Mode.BindValueChanged(_ => updateMode(), true); + ShowMaxJudgement.BindValueChanged(value => { var firstChild = CounterFlow.Children.FirstOrDefault(); From 7d1fd24ab4e8387703829fd67ca187bc0a61f374 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 18:31:25 +0900 Subject: [PATCH 157/376] Start all counters hidden to fix pop out animation when some portions are hidden --- .../HUD/JudgementCounter/JudgementCounterDisplay.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs index 0899870005..a9a3ca2cf6 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs @@ -76,8 +76,14 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter private void updateMode() { - foreach (var counter in CounterFlow.Children.Where(counter => !counter.Result.Type.IsBasic())) + foreach (var counter in CounterFlow.Children) { + if (counter.Result.Type.IsBasic()) + { + counter.Show(); + continue; + } + switch (Mode.Value) { case DisplayMode.Simple: @@ -116,7 +122,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter private JudgementCounter createCounter(JudgementTally.JudgementCount info) => new JudgementCounter(info) { - State = { Value = Visibility.Visible }, + State = { Value = Visibility.Hidden }, ShowName = { BindTarget = ShowJudgementNames } }; From 48959c0212ddbbdf8e0fd98a2ba879efbb1d9eef Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 18:35:19 +0900 Subject: [PATCH 158/376] Start name not visible to avoid pop out when hidden on startup --- osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs index 0630b73376..7675d0cc4f 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounter.cs @@ -42,6 +42,7 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter }, ResultName = new OsuSpriteText { + Alpha = 0, Font = OsuFont.Numeric.With(size: 8), Text = ruleset.Value.CreateInstance().GetDisplayNameForHitResult(Result.Type) } From 81aa7feeb5299d18d6cb02e47cce53c0b6c7e45d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 18:35:30 +0900 Subject: [PATCH 159/376] Fix using `FadeTo` on a visibility container --- .../JudgementCounterDisplay.cs | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs index a9a3ca2cf6..1d82fa5397 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs @@ -78,25 +78,27 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter { foreach (var counter in CounterFlow.Children) { - if (counter.Result.Type.IsBasic()) - { + if (shouldShow(counter)) counter.Show(); - continue; - } + else + counter.Hide(); + } + + bool shouldShow(JudgementCounter counter) + { + if (counter.Result.Type.IsBasic()) + return true; switch (Mode.Value) { case DisplayMode.Simple: - counter.Hide(); - break; + return false; case DisplayMode.Normal: - counter.FadeTo(counter.Result.Type.IsBonus() ? 0 : 1); - break; + return !counter.Result.Type.IsBonus(); case DisplayMode.All: - counter.Show(); - break; + return true; default: throw new ArgumentOutOfRangeException(); From 14649160e15f4bfd7c3bef56d26126efc7b8fd5a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 18:38:29 +0900 Subject: [PATCH 160/376] Adjust transform delay to make things feel more snappy --- .../Play/HUD/JudgementCounter/JudgementCounterDisplay.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs index 1d82fa5397..4ec90edeb0 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs @@ -16,7 +16,8 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter { public partial class JudgementCounterDisplay : CompositeDrawable, ISkinnableDrawable { - public const int TRANSFORM_DURATION = 500; + public const int TRANSFORM_DURATION = 250; + public bool UsesFixedAnchor { get; set; } [SettingSource("Display mode")] From 26cd70f2bfde476c3fe08df4ef363b6bfc10512b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 18:44:42 +0900 Subject: [PATCH 161/376] Always use production (non-experimental) endpoints for tournament client --- osu.Game.Tournament/TournamentGameBase.cs | 9 +++++++++ .../ExperimentalEndpointConfiguration.cs | 19 +++++++++++++++++++ .../Online/ProductionEndpointConfiguration.cs | 5 +---- osu.Game/OsuGameBase.cs | 4 ++-- 4 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 osu.Game/Online/ExperimentalEndpointConfiguration.cs diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs index 08f21cb556..c61ee0d3e8 100644 --- a/osu.Game.Tournament/TournamentGameBase.cs +++ b/osu.Game.Tournament/TournamentGameBase.cs @@ -16,6 +16,7 @@ using osu.Framework.IO.Stores; using osu.Framework.Logging; using osu.Framework.Platform; using osu.Game.Graphics; +using osu.Game.Online; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Tournament.IO; @@ -44,6 +45,14 @@ namespace osu.Game.Tournament return dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); } + public override EndpointConfiguration CreateEndpoints() + { + if (UseDevelopmentServer) + return base.CreateEndpoints(); + + return new ProductionEndpointConfiguration(); + } + private TournamentSpriteText initialisationText; [BackgroundDependencyLoader] diff --git a/osu.Game/Online/ExperimentalEndpointConfiguration.cs b/osu.Game/Online/ExperimentalEndpointConfiguration.cs new file mode 100644 index 0000000000..c3d0014c8b --- /dev/null +++ b/osu.Game/Online/ExperimentalEndpointConfiguration.cs @@ -0,0 +1,19 @@ +// 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.Online +{ + public class ExperimentalEndpointConfiguration : EndpointConfiguration + { + public ExperimentalEndpointConfiguration() + { + WebsiteRootUrl = @"https://osu.ppy.sh"; + APIEndpointUrl = @"https://lazer.ppy.sh"; + APIClientSecret = @"FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk"; + APIClientID = "5"; + SpectatorEndpointUrl = "https://spectator.ppy.sh/spectator"; + MultiplayerEndpointUrl = "https://spectator.ppy.sh/multiplayer"; + MetadataEndpointUrl = "https://spectator.ppy.sh/metadata"; + } + } +} diff --git a/osu.Game/Online/ProductionEndpointConfiguration.cs b/osu.Game/Online/ProductionEndpointConfiguration.cs index 003ec50afd..0244761b65 100644 --- a/osu.Game/Online/ProductionEndpointConfiguration.cs +++ b/osu.Game/Online/ProductionEndpointConfiguration.cs @@ -1,16 +1,13 @@ // 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.Online { public class ProductionEndpointConfiguration : EndpointConfiguration { public ProductionEndpointConfiguration() { - WebsiteRootUrl = @"https://osu.ppy.sh"; - APIEndpointUrl = @"https://lazer.ppy.sh"; + WebsiteRootUrl = APIEndpointUrl = @"https://osu.ppy.sh"; APIClientSecret = @"FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk"; APIClientID = "5"; SpectatorEndpointUrl = "https://spectator.ppy.sh/spectator"; diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index b27be37591..1c50349941 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -98,8 +98,8 @@ namespace osu.Game public virtual bool UseDevelopmentServer => DebugUtils.IsDebugBuild; - internal EndpointConfiguration CreateEndpoints() => - UseDevelopmentServer ? new DevelopmentEndpointConfiguration() : new ProductionEndpointConfiguration(); + public virtual EndpointConfiguration CreateEndpoints() => + UseDevelopmentServer ? new DevelopmentEndpointConfiguration() : new ExperimentalEndpointConfiguration(); public virtual Version AssemblyVersion => Assembly.GetEntryAssembly()?.GetName().Version ?? new Version(); From 68636aeaaa339d9a2dc82402d46d68bbb6004b90 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 18:56:15 +0900 Subject: [PATCH 162/376] Fix tournament client not saving changes after populating new data --- osu.Game.Tournament/TournamentGameBase.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs index 08f21cb556..e4fe922a51 100644 --- a/osu.Game.Tournament/TournamentGameBase.cs +++ b/osu.Game.Tournament/TournamentGameBase.cs @@ -156,7 +156,7 @@ namespace osu.Game.Tournament addedInfo |= addSeedingBeatmaps(); if (addedInfo) - SaveChanges(); + saveChanges(); ladder.CurrentMatch.Value = ladder.Matches.FirstOrDefault(p => p.Current.Value); } @@ -306,6 +306,11 @@ namespace osu.Game.Tournament return; } + saveChanges(); + } + + private void saveChanges() + { foreach (var r in ladder.Rounds) r.Matches = ladder.Matches.Where(p => p.Round.Value == r).Select(p => p.ID).ToList(); From 74bb44e05d668b70a53d08d1d1289e9ae9084cdd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 18:59:43 +0900 Subject: [PATCH 163/376] Fix player rank data not being re-fetched after a tournament's ruleset is changed --- osu.Game.Tournament/Screens/Setup/SetupScreen.cs | 2 +- osu.Game.Tournament/TournamentGameBase.cs | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tournament/Screens/Setup/SetupScreen.cs b/osu.Game.Tournament/Screens/Setup/SetupScreen.cs index b86513eb49..ceddd4d1a1 100644 --- a/osu.Game.Tournament/Screens/Setup/SetupScreen.cs +++ b/osu.Game.Tournament/Screens/Setup/SetupScreen.cs @@ -113,7 +113,7 @@ namespace osu.Game.Tournament.Screens.Setup new LabelledDropdown { Label = "Ruleset", - Description = "Decides what stats are displayed and which ranks are retrieved for players.", + Description = "Decides what stats are displayed and which ranks are retrieved for players. This requires a restart to reload data for an existing bracket.", Items = rulesets.AvailableRulesets, Current = LadderInfo.Ruleset, }, diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs index 08f21cb556..ed766c69df 100644 --- a/osu.Game.Tournament/TournamentGameBase.cs +++ b/osu.Game.Tournament/TournamentGameBase.cs @@ -159,6 +159,18 @@ namespace osu.Game.Tournament SaveChanges(); ladder.CurrentMatch.Value = ladder.Matches.FirstOrDefault(p => p.Current.Value); + + ladder.Ruleset.BindValueChanged(r => + { + // Refetch player rank data on next startup as the ruleset has changed. + foreach (var team in ladder.Teams) + { + foreach (var player in team.Players) + player.Rank = null; + } + + SaveChanges(); + }); } catch (Exception e) { From 00996c9f470ab5007da1e753f41c79be858ae95f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 19:11:22 +0900 Subject: [PATCH 164/376] Remove unnecessary touch interception from `OsuInputManager` --- osu.Game.Rulesets.Osu/OsuInputManager.cs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/osu.Game.Rulesets.Osu/OsuInputManager.cs b/osu.Game.Rulesets.Osu/OsuInputManager.cs index 6f69fbef43..d5eae4b391 100644 --- a/osu.Game.Rulesets.Osu/OsuInputManager.cs +++ b/osu.Game.Rulesets.Osu/OsuInputManager.cs @@ -60,19 +60,6 @@ namespace osu.Game.Rulesets.Osu return base.Handle(e); } - protected override bool HandleMouseTouchStateChange(TouchStateChangeEvent e) - { - if (!AllowUserCursorMovement) - { - // Still allow for forwarding of the "touch" part, but replace the positional data with that of the mouse. - // Primarily relied upon by the "autopilot" osu! mod. - var touch = new Touch(e.Touch.Source, CurrentState.Mouse.Position); - e = new TouchStateChangeEvent(e.State, e.Input, touch, e.IsActive, null); - } - - return base.HandleMouseTouchStateChange(e); - } - private partial class OsuKeyBindingContainer : RulesetKeyBindingContainer { private bool allowGameplayInputs = true; From 905dec913a716ae4272b8d780dad2a851446c736 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Tue, 17 Jan 2023 12:37:30 +0100 Subject: [PATCH 165/376] update skin deserialisation --- .../Archives/modified-default-20230111.osk | Bin 1685 -> 0 bytes .../Archives/modified-default-20230117.osk | Bin 0 -> 1686 bytes osu.Game.Tests/Skins/SkinDeserialisationTest.cs | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 osu.Game.Tests/Resources/Archives/modified-default-20230111.osk create mode 100644 osu.Game.Tests/Resources/Archives/modified-default-20230117.osk diff --git a/osu.Game.Tests/Resources/Archives/modified-default-20230111.osk b/osu.Game.Tests/Resources/Archives/modified-default-20230111.osk deleted file mode 100644 index 53dda9744edacb6fa6bb4f1ec5a5dbb3e2fe9317..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1685 zcmWIWW@Zs#U|`^2SRJVyrrnWvYTm-%#pVHcC5fa_;F*O{6x z&iOPeq`A$`-6GxTn0YlLx%}#-;Ij{In%z*YWEC|uF%Uk>b?^D-c-jB|R&(tu=UIDf zMePLLoRFTQ3y$+`n4z|1!$ArD1{a?Vb`52z3?ZLX1r%tg$H=jzfa z7S2h|PKWuo|4Dh+Q}}e>xz3+kGcqg}Fztl?Zxw18LVI4+{A1kKV5c;=7MF3n>IETePff23O=ZN{8+^D>6)fq8mdt@@0rgK z3CcB6{Z=ozI((yE#N3*QyX#CQ)nC~DUQ^ANv((Ao*7E=6=f}?r*U3%f$b2yUPfBjq z3Ffdp_fVaFRMl)UHxmQHD?tVZF`(0Z6EpKXLS3Bma|`nGQu9iR!G3r<{e1py1(DFpBiq9J&s4Mh+D)-^lICapXoQ^Pgx5T2Tpx@#kS)7 zl4r-xZPT_`b3BWG+rvQqpAyNhw!ONyO2y&F#=o0q{_~Z(=CeLl{z&LKFAKvPW#-HF z%v)+aF@NbQ>qTxqS5+L$KJBR-lX*e@2lJZ#Wb-vwE>y85@6afDyTf!=UggfP0O_6k zW}2M)H|4k1bgs5XebqBKfxr~T)e zZ0(N2JESMieBNrNWhlAN;_qz7nRou6rTj*z`V-ZR3=9u|nVcV(e1h}y(t}fTQj<%- z>E>u~Y&J0M*M1LAseR{k>&xjzey!Vb$7Y<#(|_c=w%lxn+EPzP!T-O5a?Q1x4b3GL z`M;}JJ}>fnx2FBVxtx|Y710f)%{nW!YUV#_Se~uMBCKsQtx}PdW9*{uQF#K90v|~&1wXM$+UkS~>U~F7)>v7wKEAi6r zC)pS53%zt~$E~{&VVP|uY#OPlryOG=WxvL&f6>1zG)rHmC9phV5rg%!_0{RmTsFLC z&y%RQcXETw!w*f5KS@T#eQ=TYx!?n|z!vYdvU?|Sc%+t%v%X~V)u#3r2!1c48>rBlT z=X{zK(%fd}ZjtVE%)FYBTz>UZ@Yx49&2A`HvWgm-7zm%`y7&BZyzKvftGV`-^Q=9# zqIQCAPDszu1;_a|%uw61;h+S6gNx4wyN0qMv}6uc_wCS?c6(Yx#fk^W*1*>*OYKWImYwCnY!Q z1asJ)d#FzLYu|i=hlzpVxgZ0B7|`jyiJ5sGp)St(xdr)osd**EU_ZQ_em?uQfynXq zKec_%t(&0x^SVO&wVPtwrp{b;cj=b}R{DJ_ltn$;W^MdmTa?WH=*@+xSM}Z+*uBtx zY5TF#|I+2JM+)n1-7j1={j05yy+!a!?JqNP8FhXEa_WoNh#V>6rt9o3eu2&p(XyUqa1o!aOL{>?$fMGb0-u&)Nh!YX8iouy)vG8 zADEw1UsAXG#;EK%Q8QBG!Y|!VY7Yau+LZ<43qA*Gt~_^8PFrfOVd;WBuD|5oUB0jV z|E2x(e`P7HjY=dQp%b zA$a*hy}R{e9cy`=-@@`2TaG+22xRU_n*T$e?=OG&!H5g{Lsm0wQ}F5j=OMA`&-XtZ zN9Tzj**iVFLrI@&(saI)7lR+fyQLI;mPSoKjZ*a|su>v=9sqMWKQR3S=jWvdr{<(4 zmw*$_(csu@VB)X+9-dPB&gs^d(~bOEx8;t_IFqOU$a!tK*$lO%o{ob5e+T87Yc(61 zODghzSFwCv$A=PmZ!`aq|)Ay?DZ22cO$|w+e+9pQd3Vk#zxA1jaUDoe_3djzD!GCdBh?H>u2k$)1SF) zc+Z|EQE~6&2APK+njU|WjEei^&G`@!Ff){k?TG5LZgw|!i1cSYxK{o?Ec_GYr#*C5J0=!w-KnhrZ L@Dq^kV+HX5+q}g^ literal 0 HcmV?d00001 diff --git a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs index f7744cb9c6..5c4f59ba2c 100644 --- a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs +++ b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs @@ -46,7 +46,7 @@ namespace osu.Game.Tests.Skins // Covers BPM counter. "Archives/modified-default-20221205.osk", // Covers judgement counter. - "Archives/modified-default-20230111.osk" + "Archives/modified-default-20230117.osk" }; /// From e65108533ab3f42a0d6a6fdfc0926d2cf02f96a0 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 17 Jan 2023 22:12:06 +0900 Subject: [PATCH 166/376] Reduce number of tested value combination 121 combinations took 2min+ --- .../TestSceneSliderFollowCircleInput.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs index 0af0ff5604..369c3d6168 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs @@ -31,9 +31,9 @@ namespace osu.Game.Rulesets.Osu.Tests [Test] public void TestMaximumDistanceTrackingWithoutMovement( - [Values(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)] + [Values(0, 5, 10)] float circleSize, - [Values(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)] + [Values(0, 5, 10)] double velocity) { const double time_slider_start = 1000; From 66441d4421ac3a1a6cf4a4748424aa72bf3558af Mon Sep 17 00:00:00 2001 From: tsrk Date: Tue, 17 Jan 2023 13:16:11 +0000 Subject: [PATCH 167/376] test: remove test for ArgonSongProgressGraph --- .../TestSceneArgonSongProgressGraph.cs | 69 ------------------- 1 file changed, 69 deletions(-) delete mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneArgonSongProgressGraph.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneArgonSongProgressGraph.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneArgonSongProgressGraph.cs deleted file mode 100644 index e7feadc72b..0000000000 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneArgonSongProgressGraph.cs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Collections.Generic; -using System.Diagnostics; -using NUnit.Framework; -using osu.Framework.Graphics; -using osu.Framework.Testing; -using osu.Framework.Utils; -using osu.Game.Rulesets.Objects; -using osu.Game.Screens.Play.HUD; - -namespace osu.Game.Tests.Visual.Gameplay -{ - [TestFixture] - public partial class TestSceneArgonSongProgressGraph : OsuTestScene - { - private TestArgonSongProgressGraph? graph; - - [SetUpSteps] - public void SetupSteps() - { - AddStep("add new big graph", () => - { - if (graph != null) - { - graph.Expire(); - graph = null; - } - - Add(graph = new TestArgonSongProgressGraph - { - RelativeSizeAxes = Axes.X, - Height = 200, - Anchor = Anchor.TopLeft, - Origin = Anchor.TopLeft, - }); - }); - } - - [Test] - public void Test() - { - AddAssert("ensure not created", () => graph!.CreationCount == 0); - AddStep("display values", displayRandomValues); - } - - private void displayRandomValues() - { - Debug.Assert(graph != null); - var objects = new List(); - for (double i = 0; i < 5000; i += RNG.NextDouble() * 10 + i / 1000) - objects.Add(new HitObject { StartTime = i }); - - graph.Objects = objects; - } - - private partial class TestArgonSongProgressGraph : ArgonSongProgressGraph - { - public int CreationCount { get; private set; } - - protected override void RecreateGraph() - { - base.RecreateGraph(); - CreationCount++; - } - } - } -} From d91aa341e511285d00e682ea8781ac31a1dfc16b Mon Sep 17 00:00:00 2001 From: tsrk Date: Tue, 17 Jan 2023 13:16:47 +0000 Subject: [PATCH 168/376] refactor(ArgonSongProgress): reorder layering and make density graph visible for past time --- .../Screens/Play/HUD/ArgonSongProgress.cs | 29 +++++++++++++------ .../Screens/Play/HUD/ArgonSongProgressBar.cs | 19 ++++++++++-- .../Play/HUD/ArgonSongProgressGraph.cs | 4 +-- 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs b/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs index e5ee42e72a..8446abecd2 100644 --- a/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs +++ b/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Timing; using osu.Game.Configuration; using osu.Game.Graphics; @@ -18,6 +19,7 @@ namespace osu.Game.Screens.Play.HUD private readonly SongProgressInfo info; private readonly ArgonSongProgressGraph graph; private readonly ArgonSongProgressBar bar; + private readonly Container graphContainer; private const float bar_height = 10; @@ -38,6 +40,8 @@ namespace osu.Game.Screens.Play.HUD { Anchor = Anchor.BottomCentre; Origin = Anchor.BottomCentre; + Masking = true; + CornerRadius = 5; Children = new Drawable[] { info = new SongProgressInfo @@ -48,20 +52,27 @@ namespace osu.Game.Screens.Play.HUD RelativeSizeAxes = Axes.X, ShowProgress = false }, - graph = new ArgonSongProgressGraph - { - Name = "Difficulty graph", - Origin = Anchor.BottomLeft, - Anchor = Anchor.BottomLeft, - RelativeSizeAxes = Axes.X, - }, bar = new ArgonSongProgressBar(bar_height) { Name = "Seek bar", Origin = Anchor.BottomLeft, Anchor = Anchor.BottomLeft, OnSeek = time => player?.Seek(time), - } + }, + graphContainer = new Container + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Masking = true, + CornerRadius = 5, + Child = graph = new ArgonSongProgressGraph + { + Name = "Difficulty graph", + RelativeSizeAxes = Axes.Both, + Blending = BlendingParameters.Additive + }, + RelativeSizeAxes = Axes.X, + }, }; RelativeSizeAxes = Axes.X; } @@ -111,7 +122,7 @@ namespace osu.Game.Screens.Play.HUD { base.Update(); Height = bar.Height + bar_height + info.Height; - graph.Height = bar.Height; + graphContainer.Height = bar.Height; } protected override void PopIn() diff --git a/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs b/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs index 3ac7223f1d..d87359397e 100644 --- a/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs +++ b/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs @@ -4,6 +4,7 @@ using System; 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; @@ -30,12 +31,19 @@ namespace osu.Game.Screens.Play.HUD private readonly BindableBool showBackground = new BindableBool(); + private readonly ColourInfo mainColour; + private readonly ColourInfo mainColourDarkened; + private ColourInfo altColour; + private ColourInfo altColourDarkened; + public bool ShowBackground { get => showBackground.Value; set => showBackground.Value = value; } + public BindableBool Darken = new BindableBool(); + private const float alpha_threshold = 2500; public Action? OnSeek { get; set; } @@ -91,6 +99,7 @@ namespace osu.Game.Screens.Play.HUD { RelativeSizeAxes = Axes.Both, Alpha = 0, + Colour = Colour4.White.Darken(1 + 1 / 4f) }, catchupBar = new RoundedBar { @@ -107,11 +116,12 @@ namespace osu.Game.Screens.Play.HUD Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, CornerRadius = 5, - AccentColour = Color4.White, + AccentColour = mainColour = Color4.White, RelativeSizeAxes = Axes.Both }, }; catchupBaseDepth = catchupBar.Depth; + mainColourDarkened = Colour4.White.Darken(1 / 3f); } private void setupAlternateValue() @@ -135,13 +145,16 @@ namespace osu.Game.Screens.Play.HUD [BackgroundDependencyLoader] private void load(OsuColour colours) { - catchupBar.AccentColour = colours.BlueLight; + catchupBar.AccentColour = altColour = colours.BlueLight; + altColourDarkened = colours.BlueLight.Darken(1 / 3f); showBackground.BindValueChanged(_ => updateBackground(), true); } private void updateBackground() { - background.FadeTo(showBackground.Value ? 1 : 0, 200, Easing.In); + background.FadeTo(showBackground.Value ? 1 / 4f : 0, 200, Easing.In); + catchupBar.TransformTo(nameof(catchupBar.AccentColour), ShowBackground ? altColour : altColourDarkened, 200, Easing.In); + playfieldBar.TransformTo(nameof(playfieldBar.AccentColour), ShowBackground ? mainColour : mainColourDarkened, 200, Easing.In); } protected override bool OnHover(HoverEvent e) diff --git a/osu.Game/Screens/Play/HUD/ArgonSongProgressGraph.cs b/osu.Game/Screens/Play/HUD/ArgonSongProgressGraph.cs index 577d79886c..0899476ed4 100644 --- a/osu.Game/Screens/Play/HUD/ArgonSongProgressGraph.cs +++ b/osu.Game/Screens/Play/HUD/ArgonSongProgressGraph.cs @@ -20,7 +20,7 @@ namespace osu.Game.Screens.Play.HUD { objects = value; - const int granularity = 300; + const int granularity = 200; int[] values = new int[granularity]; if (!objects.Any()) @@ -56,7 +56,7 @@ namespace osu.Game.Screens.Play.HUD var colours = new List(); for (int i = 0; i < 5; i++) - colours.Add(Colour4.White.Opacity(1 / 5f * 0.85f)); + colours.Add(Colour4.White.Darken(1 + 1 / 5f).Opacity(1 / 5f)); TierColours = colours; } 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 169/376] 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 170/376] 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 8e1002b7448e1045f12cea690ed50c2e3361c6ed Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 01:56:12 +0900 Subject: [PATCH 171/376] Fix song select potentially operating on `Carousel` before it is fully loaded Should fix test failures like https://github.com/ppy/osu/actions/runs/3939620830/jobs/6739690253. --- osu.Game/Screens/Select/SongSelect.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 64deb59026..db4d326991 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -860,9 +860,13 @@ namespace osu.Game.Screens.Select Logger.Log($"decoupled ruleset transferred (\"{decoupledRuleset.Value}\" -> \"{Ruleset.Value}\")"); rulesetNoDebounce = decoupledRuleset.Value = Ruleset.Value; - // if we have a pending filter operation, we want to run it now. - // it could change selection (ie. if the ruleset has been changed). - Carousel.FlushPendingFilterOperations(); + if (Carousel.IsLoaded) + { + // if we have a pending filter operation, we want to run it now. + // it could change selection (ie. if the ruleset has been changed). + Carousel.FlushPendingFilterOperations(); + } + return true; } From 452bf9255023fe6a7ac9c62e6856af7d721b4b3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 17 Jan 2023 18:02:06 +0100 Subject: [PATCH 172/376] Fix code quality inspection --- .../TestSceneSliderFollowCircleInput.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs index 369c3d6168..a32f0a13b8 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs @@ -31,10 +31,8 @@ namespace osu.Game.Rulesets.Osu.Tests [Test] public void TestMaximumDistanceTrackingWithoutMovement( - [Values(0, 5, 10)] - float circleSize, - [Values(0, 5, 10)] - double velocity) + [Values(0, 5, 10)] float circleSize, + [Values(0, 5, 10)] double velocity) { const double time_slider_start = 1000; From f1989ba24d93717eac9843dfd8eb9984941a65dc Mon Sep 17 00:00:00 2001 From: tsrk Date: Tue, 17 Jan 2023 17:26:05 +0000 Subject: [PATCH 173/376] quality: remove unused `Darken` bindable boolean --- osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs b/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs index d87359397e..ff999aa6a3 100644 --- a/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs +++ b/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs @@ -42,8 +42,6 @@ namespace osu.Game.Screens.Play.HUD set => showBackground.Value = value; } - public BindableBool Darken = new BindableBool(); - private const float alpha_threshold = 2500; public Action? OnSeek { get; set; } From 97bd76efc6638c4994c06442c3bcd28057bd9672 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 17 Jan 2023 09:47:42 -0800 Subject: [PATCH 174/376] Add ability to easily mention users in chat by right clicking username --- osu.Game/Localisation/ChatStrings.cs | 5 +++++ osu.Game/Online/Chat/StandAloneChatDisplay.cs | 1 + osu.Game/Overlays/Chat/DrawableUsername.cs | 13 +++++++++++++ 3 files changed, 19 insertions(+) diff --git a/osu.Game/Localisation/ChatStrings.cs b/osu.Game/Localisation/ChatStrings.cs index 7bd284a94e..6b0a6bd8e1 100644 --- a/osu.Game/Localisation/ChatStrings.cs +++ b/osu.Game/Localisation/ChatStrings.cs @@ -19,6 +19,11 @@ namespace osu.Game.Localisation /// public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"join the real-time discussion"); + /// + /// "Mention" + /// + public static LocalisableString MentionUser => new TranslatableString(getKey(@"mention_user"), @"Mention"); + private static string getKey(string key) => $"{prefix}:{key}"; } } diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs index 0a5434822b..e3b5037367 100644 --- a/osu.Game/Online/Chat/StandAloneChatDisplay.cs +++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs @@ -25,6 +25,7 @@ namespace osu.Game.Online.Chat /// public partial class StandAloneChatDisplay : CompositeDrawable { + [Cached] public readonly Bindable Channel = new Bindable(); protected readonly ChatTextBox TextBox; diff --git a/osu.Game/Overlays/Chat/DrawableUsername.cs b/osu.Game/Overlays/Chat/DrawableUsername.cs index 8cd16047f3..73eb335e99 100644 --- a/osu.Game/Overlays/Chat/DrawableUsername.cs +++ b/osu.Game/Overlays/Chat/DrawableUsername.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -24,6 +25,7 @@ using osu.Game.Online.Chat; using osu.Game.Resources.Localisation.Web; using osuTK; using osuTK.Graphics; +using ChatStrings = osu.Game.Localisation.ChatStrings; namespace osu.Game.Overlays.Chat { @@ -65,6 +67,9 @@ namespace osu.Game.Overlays.Chat [Resolved(canBeNull: true)] private UserProfileOverlay? profileOverlay { get; set; } + [Resolved] + private Bindable? currentChannel { get; set; } + private readonly APIUser user; private readonly OsuSpriteText drawableText; @@ -156,6 +161,14 @@ namespace osu.Game.Overlays.Chat if (!user.Equals(api.LocalUser.Value)) items.Add(new OsuMenuItem(UsersStrings.CardSendMessage, MenuItemType.Standard, openUserChannel)); + if (currentChannel != null) + { + items.Add(new OsuMenuItem(ChatStrings.MentionUser, MenuItemType.Standard, () => + { + currentChannel.Value.TextBoxMessage.Value += $"@{user.Username}"; + })); + } + return items.ToArray(); } } From b8e6a2d87b86c88f243bd67ee6379d572ca1c5b3 Mon Sep 17 00:00:00 2001 From: Wleter Date: Tue, 17 Jan 2023 20:41:49 +0100 Subject: [PATCH 175/376] 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 176/376] 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 177/376] 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 364034280563cfd683136e9c005e91801fc3a678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 17 Jan 2023 21:30:46 +0100 Subject: [PATCH 178/376] Add logging on comment post failure --- osu.Game/Overlays/Comments/CommentsContainer.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 3639fe1835..a334fac215 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -19,6 +19,7 @@ using osu.Framework.Threading; using System.Collections.Generic; using JetBrains.Annotations; using osu.Framework.Localisation; +using osu.Framework.Logging; using osu.Game.Graphics.Sprites; using osu.Game.Resources.Localisation.Web; using osu.Game.Users.Drawables; @@ -420,9 +421,10 @@ namespace osu.Game.Overlays.Comments { ShowLoadingSpinner = true; CommentPostRequest req = new CommentPostRequest(commentsContainer.Type.Value, commentsContainer.Id.Value, text); - req.Failure += _ => Schedule(() => + req.Failure += e => Schedule(() => { ShowLoadingSpinner = false; + Logger.Error(e, "Posting comment failed."); }); req.Success += cb => Schedule(() => { From 350cce1315d050b8d466edd3549ad309517fe8d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 31 Dec 2022 18:39:36 +0100 Subject: [PATCH 179/376] Move contents of detail header to separate component --- .../Profile/Header/Components/MainDetails.cs | 187 ++++++++++++++++++ .../Profile/Header/DetailHeaderContainer.cs | 161 +-------------- 2 files changed, 190 insertions(+), 158 deletions(-) create mode 100644 osu.Game/Overlays/Profile/Header/Components/MainDetails.cs diff --git a/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs b/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs new file mode 100644 index 0000000000..930ba29c7f --- /dev/null +++ b/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs @@ -0,0 +1,187 @@ +// 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.Bindables; +using osu.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.Leaderboards; +using osu.Game.Resources.Localisation.Web; +using osu.Game.Scoring; +using osuTK; + +namespace osu.Game.Overlays.Profile.Header.Components +{ + public partial class MainDetails : CompositeDrawable + { + private readonly Dictionary scoreRankInfos = new Dictionary(); + private ProfileValueDisplay medalInfo = null!; + private ProfileValueDisplay ppInfo = null!; + private ProfileValueDisplay detailGlobalRank = null!; + private ProfileValueDisplay detailCountryRank = null!; + private RankGraph rankGraph = null!; + + public readonly Bindable User = new Bindable(); + + [BackgroundDependencyLoader] + private void load() + { + AutoSizeAxes = Axes.Y; + + InternalChild = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + AutoSizeDuration = 200, + AutoSizeEasing = Easing.OutQuint, + Masking = true, + Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 }, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 15), + Children = new Drawable[] + { + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(20), + Children = new Drawable[] + { + detailGlobalRank = new ProfileValueDisplay(true) + { + Title = UsersStrings.ShowRankGlobalSimple, + }, + detailCountryRank = new ProfileValueDisplay(true) + { + Title = UsersStrings.ShowRankCountrySimple, + }, + } + }, + new Container + { + RelativeSizeAxes = Axes.X, + Height = 60, + Children = new Drawable[] + { + rankGraph = new RankGraph + { + RelativeSizeAxes = Axes.Both, + }, + } + }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Children = new Drawable[] + { + medalInfo = new ProfileValueDisplay + { + Title = UsersStrings.ShowStatsMedals, + }, + ppInfo = new ProfileValueDisplay + { + Title = "pp", + }, + new TotalPlayTime + { + User = { BindTarget = User } + }, + } + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5), + Children = new[] + { + scoreRankInfos[ScoreRank.XH] = new ScoreRankInfo(ScoreRank.XH), + scoreRankInfos[ScoreRank.X] = new ScoreRankInfo(ScoreRank.X), + scoreRankInfos[ScoreRank.SH] = new ScoreRankInfo(ScoreRank.SH), + scoreRankInfos[ScoreRank.S] = new ScoreRankInfo(ScoreRank.S), + scoreRankInfos[ScoreRank.A] = new ScoreRankInfo(ScoreRank.A), + } + } + } + }, + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + User.BindValueChanged(e => updateDisplay(e.NewValue), true); + } + + private void updateDisplay(UserProfileData? data) + { + var user = data?.User; + + medalInfo.Content = user?.Achievements?.Length.ToString() ?? "0"; + ppInfo.Content = user?.Statistics?.PP?.ToLocalisableString("#,##0") ?? (LocalisableString)"0"; + + foreach (var scoreRankInfo in scoreRankInfos) + scoreRankInfo.Value.RankCount = user?.Statistics?.GradesCount[scoreRankInfo.Key] ?? 0; + + detailGlobalRank.Content = user?.Statistics?.GlobalRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; + detailCountryRank.Content = user?.Statistics?.CountryRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; + + rankGraph.Statistics.Value = user?.Statistics; + } + + private partial class ScoreRankInfo : CompositeDrawable + { + private readonly OsuSpriteText rankCount; + + public int RankCount + { + set => rankCount.Text = value.ToLocalisableString("#,##0"); + } + + public ScoreRankInfo(ScoreRank rank) + { + AutoSizeAxes = Axes.Both; + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + Width = 44, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new DrawableRank(rank) + { + RelativeSizeAxes = Axes.X, + Height = 22, + }, + rankCount = new OsuSpriteText + { + Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre + } + } + }; + } + } + } +} diff --git a/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs index 890e6c4e04..17de8b8ba0 100644 --- a/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs @@ -1,33 +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 System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Localisation; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Online.Leaderboards; using osu.Game.Overlays.Profile.Header.Components; -using osu.Game.Resources.Localisation.Web; -using osu.Game.Scoring; -using osuTK; namespace osu.Game.Overlays.Profile.Header { public partial class DetailHeaderContainer : CompositeDrawable { - private readonly Dictionary scoreRankInfos = new Dictionary(); - private ProfileValueDisplay medalInfo = null!; - private ProfileValueDisplay ppInfo = null!; - private ProfileValueDisplay detailGlobalRank = null!; - private ProfileValueDisplay detailCountryRank = null!; - private RankGraph rankGraph = null!; - public readonly Bindable User = new Bindable(); [BackgroundDependencyLoader] @@ -35,8 +19,6 @@ namespace osu.Game.Overlays.Profile.Header { AutoSizeAxes = Axes.Y; - User.ValueChanged += e => updateDisplay(e.NewValue); - InternalChildren = new Drawable[] { new Box @@ -44,149 +26,12 @@ namespace osu.Game.Overlays.Profile.Header RelativeSizeAxes = Axes.Both, Colour = colourProvider.Background5, }, - new FillFlowContainer + new MainDetails { RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - AutoSizeDuration = 200, - AutoSizeEasing = Easing.OutQuint, - Masking = true, - Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 }, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 15), - Children = new Drawable[] - { - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(20), - Children = new Drawable[] - { - detailGlobalRank = new ProfileValueDisplay(true) - { - Title = UsersStrings.ShowRankGlobalSimple, - }, - detailCountryRank = new ProfileValueDisplay(true) - { - Title = UsersStrings.ShowRankCountrySimple, - }, - } - }, - new Container - { - RelativeSizeAxes = Axes.X, - Height = 60, - Children = new Drawable[] - { - rankGraph = new RankGraph - { - RelativeSizeAxes = Axes.Both, - }, - } - }, - new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] - { - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10, 0), - Children = new Drawable[] - { - medalInfo = new ProfileValueDisplay - { - Title = UsersStrings.ShowStatsMedals, - }, - ppInfo = new ProfileValueDisplay - { - Title = "pp", - }, - new TotalPlayTime - { - User = { BindTarget = User } - }, - } - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(5), - Children = new[] - { - scoreRankInfos[ScoreRank.XH] = new ScoreRankInfo(ScoreRank.XH), - scoreRankInfos[ScoreRank.X] = new ScoreRankInfo(ScoreRank.X), - scoreRankInfos[ScoreRank.SH] = new ScoreRankInfo(ScoreRank.SH), - scoreRankInfos[ScoreRank.S] = new ScoreRankInfo(ScoreRank.S), - scoreRankInfos[ScoreRank.A] = new ScoreRankInfo(ScoreRank.A), - } - } - } - }, - } - }, + User = { BindTarget = User } + } }; } - - private void updateDisplay(UserProfileData? data) - { - var user = data?.User; - - medalInfo.Content = user?.Achievements?.Length.ToString() ?? "0"; - ppInfo.Content = user?.Statistics?.PP?.ToLocalisableString("#,##0") ?? (LocalisableString)"0"; - - foreach (var scoreRankInfo in scoreRankInfos) - scoreRankInfo.Value.RankCount = user?.Statistics?.GradesCount[scoreRankInfo.Key] ?? 0; - - detailGlobalRank.Content = user?.Statistics?.GlobalRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; - detailCountryRank.Content = user?.Statistics?.CountryRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; - - rankGraph.Statistics.Value = user?.Statistics; - } - - private partial class ScoreRankInfo : CompositeDrawable - { - private readonly OsuSpriteText rankCount; - - public int RankCount - { - set => rankCount.Text = value.ToLocalisableString("#,##0"); - } - - public ScoreRankInfo(ScoreRank rank) - { - AutoSizeAxes = Axes.Both; - InternalChild = new FillFlowContainer - { - AutoSizeAxes = Axes.Y, - Width = 44, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new DrawableRank(rank) - { - RelativeSizeAxes = Axes.X, - Height = 22, - }, - rankCount = new OsuSpriteText - { - Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre - } - } - }; - } - } } } From 7a475d9cf8b160ad9ce77ba283c8b4696298c2aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 31 Dec 2022 18:55:27 +0100 Subject: [PATCH 180/376] Move out stats from top header container --- .../Header/Components/ExtendedDetails.cs | 108 ++++++++++++++++++ .../Profile/Header/TopHeaderContainer.cs | 51 --------- 2 files changed, 108 insertions(+), 51 deletions(-) create mode 100644 osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs diff --git a/osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs b/osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs new file mode 100644 index 0000000000..b50b0041d0 --- /dev/null +++ b/osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.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 osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Resources.Localisation.Web; +using osu.Game.Users; +using osuTK; + +namespace osu.Game.Overlays.Profile.Header.Components +{ + public partial class ExtendedDetails : CompositeDrawable + { + public Bindable UserProfile { get; } = new Bindable(); + + private SpriteText rankedScore = null!; + private SpriteText hitAccuracy = null!; + private SpriteText playCount = null!; + private SpriteText totalScore = null!; + private SpriteText totalHits = null!; + private SpriteText maximumCombo = null!; + private SpriteText replaysWatched = null!; + + [BackgroundDependencyLoader] + private void load() + { + var font = OsuFont.Default.With(size: 12); + const float vertical_spacing = 4; + + AutoSizeAxes = Axes.Both; + + // this should really be a grid, but trying to avoid one to avoid the performance hit. + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(20, 0), + Children = new[] + { + new FillFlowContainer + { + Name = @"Labels", + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, vertical_spacing), + Children = new Drawable[] + { + new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsRankedScore }, + new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsHitAccuracy }, + new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsPlayCount }, + new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsTotalScore }, + new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsTotalHits }, + new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsMaximumCombo }, + new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsReplaysWatchedByOthers }, + } + }, + new FillFlowContainer + { + Name = @"Values", + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, vertical_spacing), + Children = new Drawable[] + { + rankedScore = new OsuSpriteText { Font = font }, + hitAccuracy = new OsuSpriteText { Font = font }, + playCount = new OsuSpriteText { Font = font }, + totalScore = new OsuSpriteText { Font = font }, + totalHits = new OsuSpriteText { Font = font }, + maximumCombo = new OsuSpriteText { Font = font }, + replaysWatched = new OsuSpriteText { Font = font }, + } + }, + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + UserProfile.BindValueChanged(userProfile => updateStatistics(userProfile.NewValue?.User.Statistics), true); + } + + private void updateStatistics(UserStatistics? statistics) + { + if (statistics == null) + { + Alpha = 0; + return; + } + + Alpha = 1; + + rankedScore.Text = statistics.RankedScore.ToLocalisableString(@"N0"); + hitAccuracy.Text = statistics.DisplayAccuracy; + playCount.Text = statistics.PlayCount.ToLocalisableString(@"N0"); + totalScore.Text = statistics.TotalScore.ToLocalisableString(@"N0"); + totalHits.Text = statistics.TotalHits.ToLocalisableString(@"N0"); + maximumCombo.Text = statistics.MaxCombo.ToLocalisableString(@"N0"); + replaysWatched.Text = statistics.ReplaysWatched.ToLocalisableString(@"N0"); + } + } +} diff --git a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs index e04a8ad9ad..1fe39cb570 100644 --- a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs @@ -5,18 +5,15 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Overlays.Profile.Header.Components; -using osu.Game.Resources.Localisation.Web; using osu.Game.Users.Drawables; using osuTK; @@ -38,7 +35,6 @@ namespace osu.Game.Overlays.Profile.Header private OsuSpriteText titleText = null!; private UpdateableFlag userFlag = null!; private OsuSpriteText userCountryText = null!; - private FillFlowContainer userStats = null!; private GroupBadgeFlow groupBadgeFlow = null!; [BackgroundDependencyLoader] @@ -164,16 +160,6 @@ namespace osu.Game.Overlays.Profile.Header } } }, - userStats = new FillFlowContainer - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - AutoSizeAxes = Axes.Y, - Width = 300, - Margin = new MarginPadding { Right = UserProfileOverlay.CONTENT_X_MARGIN }, - Padding = new MarginPadding { Vertical = 15 }, - Spacing = new Vector2(0, 2) - } }; User.BindValueChanged(user => updateUser(user.NewValue)); @@ -192,43 +178,6 @@ namespace osu.Game.Overlays.Profile.Header titleText.Text = user?.Title ?? string.Empty; titleText.Colour = Color4Extensions.FromHex(user?.Colour ?? "fff"); groupBadgeFlow.User.Value = user; - - userStats.Clear(); - - if (user?.Statistics != null) - { - userStats.Add(new UserStatsLine(UsersStrings.ShowStatsRankedScore, user.Statistics.RankedScore.ToLocalisableString("#,##0"))); - userStats.Add(new UserStatsLine(UsersStrings.ShowStatsHitAccuracy, user.Statistics.DisplayAccuracy)); - userStats.Add(new UserStatsLine(UsersStrings.ShowStatsPlayCount, user.Statistics.PlayCount.ToLocalisableString("#,##0"))); - userStats.Add(new UserStatsLine(UsersStrings.ShowStatsTotalScore, user.Statistics.TotalScore.ToLocalisableString("#,##0"))); - userStats.Add(new UserStatsLine(UsersStrings.ShowStatsTotalHits, user.Statistics.TotalHits.ToLocalisableString("#,##0"))); - userStats.Add(new UserStatsLine(UsersStrings.ShowStatsMaximumCombo, user.Statistics.MaxCombo.ToLocalisableString("#,##0"))); - userStats.Add(new UserStatsLine(UsersStrings.ShowStatsReplaysWatchedByOthers, user.Statistics.ReplaysWatched.ToLocalisableString("#,##0"))); - } - } - - private partial class UserStatsLine : Container - { - public UserStatsLine(LocalisableString left, LocalisableString right) - { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - Children = new Drawable[] - { - new OsuSpriteText - { - Font = OsuFont.GetFont(size: 15), - Text = left, - }, - new OsuSpriteText - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Font = OsuFont.GetFont(size: 15, weight: FontWeight.Bold), - Text = right, - }, - }; - } } } } From f7c942ac10b22d365f9f9b98228959d8c5d8350e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 31 Dec 2022 19:00:40 +0100 Subject: [PATCH 181/376] Move user stats into detail header container --- .../Header/Components/ExtendedDetails.cs | 6 ++- .../Profile/Header/Components/MainDetails.cs | 1 - .../Profile/Header/DetailHeaderContainer.cs | 44 ++++++++++++++++++- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs b/osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs index b50b0041d0..50fc52600c 100644 --- a/osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs +++ b/osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs @@ -17,7 +17,7 @@ namespace osu.Game.Overlays.Profile.Header.Components { public partial class ExtendedDetails : CompositeDrawable { - public Bindable UserProfile { get; } = new Bindable(); + public Bindable User { get; } = new Bindable(); private SpriteText rankedScore = null!; private SpriteText hitAccuracy = null!; @@ -46,6 +46,7 @@ namespace osu.Game.Overlays.Profile.Header.Components new FillFlowContainer { Name = @"Labels", + AutoSizeAxes = Axes.Both, Direction = FillDirection.Vertical, Spacing = new Vector2(0, vertical_spacing), Children = new Drawable[] @@ -62,6 +63,7 @@ namespace osu.Game.Overlays.Profile.Header.Components new FillFlowContainer { Name = @"Values", + AutoSizeAxes = Axes.Both, Direction = FillDirection.Vertical, Spacing = new Vector2(0, vertical_spacing), Children = new Drawable[] @@ -83,7 +85,7 @@ namespace osu.Game.Overlays.Profile.Header.Components { base.LoadComplete(); - UserProfile.BindValueChanged(userProfile => updateStatistics(userProfile.NewValue?.User.Statistics), true); + User.BindValueChanged(user => updateStatistics(user.NewValue?.User.Statistics), true); } private void updateStatistics(UserStatistics? statistics) diff --git a/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs b/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs index 930ba29c7f..b89973c5e5 100644 --- a/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs +++ b/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs @@ -40,7 +40,6 @@ namespace osu.Game.Overlays.Profile.Header.Components AutoSizeDuration = 200, AutoSizeEasing = Easing.OutQuint, Masking = true, - Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 }, Direction = FillDirection.Vertical, Spacing = new Vector2(0, 15), Children = new Drawable[] diff --git a/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs index 17de8b8ba0..1cc3aae735 100644 --- a/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs @@ -26,10 +26,50 @@ namespace osu.Game.Overlays.Profile.Header RelativeSizeAxes = Axes.Both, Colour = colourProvider.Background5, }, - new MainDetails + new Container { RelativeSizeAxes = Axes.X, - User = { BindTarget = User } + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 }, + Child = new GridContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + }, + ColumnDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.AutoSize), + }, + Content = new[] + { + new Drawable[] + { + new MainDetails + { + RelativeSizeAxes = Axes.X, + User = { BindTarget = User } + }, + new Box + { + RelativeSizeAxes = Axes.Y, + Width = 2, + Colour = colourProvider.Background6, + Margin = new MarginPadding { Horizontal = 15 } + }, + new ExtendedDetails + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + User = { BindTarget = User } + } + } + } + } } }; } From 254c881ded6bc1c7b7875d3fe07ab88a02a39409 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 17 Jan 2023 14:12:48 -0800 Subject: [PATCH 182/376] Also check null for bindable channel value --- osu.Game/Overlays/Chat/DrawableUsername.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Chat/DrawableUsername.cs b/osu.Game/Overlays/Chat/DrawableUsername.cs index 73eb335e99..771ccdcbef 100644 --- a/osu.Game/Overlays/Chat/DrawableUsername.cs +++ b/osu.Game/Overlays/Chat/DrawableUsername.cs @@ -68,7 +68,7 @@ namespace osu.Game.Overlays.Chat private UserProfileOverlay? profileOverlay { get; set; } [Resolved] - private Bindable? currentChannel { get; set; } + private Bindable? currentChannel { get; set; } private readonly APIUser user; private readonly OsuSpriteText drawableText; @@ -161,7 +161,7 @@ namespace osu.Game.Overlays.Chat if (!user.Equals(api.LocalUser.Value)) items.Add(new OsuMenuItem(UsersStrings.CardSendMessage, MenuItemType.Standard, openUserChannel)); - if (currentChannel != null) + if (currentChannel?.Value != null) { items.Add(new OsuMenuItem(ChatStrings.MentionUser, MenuItemType.Standard, () => { From dfea42fd163f0ec8c558ba2b954a054a2af2d10c Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 17 Jan 2023 14:13:50 -0800 Subject: [PATCH 183/376] Add space after username mention --- osu.Game/Overlays/Chat/DrawableUsername.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Chat/DrawableUsername.cs b/osu.Game/Overlays/Chat/DrawableUsername.cs index 771ccdcbef..031a0b6ae2 100644 --- a/osu.Game/Overlays/Chat/DrawableUsername.cs +++ b/osu.Game/Overlays/Chat/DrawableUsername.cs @@ -165,7 +165,7 @@ namespace osu.Game.Overlays.Chat { items.Add(new OsuMenuItem(ChatStrings.MentionUser, MenuItemType.Standard, () => { - currentChannel.Value.TextBoxMessage.Value += $"@{user.Username}"; + currentChannel.Value.TextBoxMessage.Value += $"@{user.Username} "; })); } From 12544c16eab2510ce4c8d90ba415103ba632b364 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Wed, 18 Jan 2023 02:10:02 +0300 Subject: [PATCH 184/376] Remove canBeNull --- osu.Game/Overlays/Comments/DrawableComment.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 834abd5e9f..70ffbd8baf 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -70,7 +70,7 @@ namespace osu.Game.Overlays.Comments private GridContainer content = null!; private VotePill votePill = null!; - [Resolved(canBeNull: true)] + [Resolved] private IDialogOverlay? dialogOverlay { get; set; } [Resolved] @@ -79,7 +79,7 @@ namespace osu.Game.Overlays.Comments [Resolved] private GameHost host { get; set; } = null!; - [Resolved(canBeNull: true)] + [Resolved] private OnScreenDisplay? onScreenDisplay { get; set; } public DrawableComment(Comment comment) From ca3be7138149e9ed8f6af73986cef0b559fa60f6 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Wed, 18 Jan 2023 02:11:07 +0300 Subject: [PATCH 185/376] Track comment's nesting and reduce padding for too nested --- osu.Game/Overlays/Comments/DrawableComment.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 70ffbd8baf..1df65ab4b1 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -57,6 +57,11 @@ namespace osu.Game.Overlays.Comments /// public bool WasDeleted { get; protected set; } + /// + /// Tracks this comment's level of nesting. 0 means that this comment has no parents. + /// + public int Level { get; private set; } + private FillFlowContainer childCommentsVisibilityContainer = null!; private FillFlowContainer childCommentsContainer = null!; private LoadRepliesButton loadRepliesButton = null!; @@ -88,12 +93,16 @@ namespace osu.Game.Overlays.Comments } [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) + private void load(OverlayColourProvider colourProvider, DrawableComment? parentComment) { LinkFlowContainer username; FillFlowContainer info; CommentMarkdownContainer message; + Level = parentComment?.Level + 1 ?? 0; + + float childrenPadding = Level < 6 ? 20 : 5; + RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; InternalChildren = new Drawable[] @@ -248,7 +257,7 @@ namespace osu.Game.Overlays.Comments RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Direction = FillDirection.Vertical, - Padding = new MarginPadding { Left = 20 }, + Padding = new MarginPadding { Left = childrenPadding }, Children = new Drawable[] { childCommentsContainer = new FillFlowContainer From 4ad79a8a0ac721be0e409a9fd729a45d5c6c1bd0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 12:00:47 +0900 Subject: [PATCH 186/376] Move `IsLoaded` check inside `BeatmapCarousel` --- osu.Game/Screens/Select/BeatmapCarousel.cs | 3 +++ osu.Game/Screens/Select/SongSelect.cs | 9 +++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 19eced08d9..774ecc2c9c 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -596,6 +596,9 @@ namespace osu.Game.Screens.Select public void FlushPendingFilterOperations() { + if (!IsLoaded) + return; + if (PendingFilter?.Completed == false) { applyActiveCriteria(false); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index db4d326991..4b3222c14a 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -860,12 +860,9 @@ namespace osu.Game.Screens.Select Logger.Log($"decoupled ruleset transferred (\"{decoupledRuleset.Value}\" -> \"{Ruleset.Value}\")"); rulesetNoDebounce = decoupledRuleset.Value = Ruleset.Value; - if (Carousel.IsLoaded) - { - // if we have a pending filter operation, we want to run it now. - // it could change selection (ie. if the ruleset has been changed). - Carousel.FlushPendingFilterOperations(); - } + // if we have a pending filter operation, we want to run it now. + // it could change selection (ie. if the ruleset has been changed). + Carousel.FlushPendingFilterOperations(); return true; } From 3630b41a5b182f68249f70d29a33ce71f7910894 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 13:13:20 +0900 Subject: [PATCH 187/376] Remove unused usings --- osu.Game.Rulesets.Osu/OsuInputManager.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/OsuInputManager.cs b/osu.Game.Rulesets.Osu/OsuInputManager.cs index d5eae4b391..99ae706369 100644 --- a/osu.Game.Rulesets.Osu/OsuInputManager.cs +++ b/osu.Game.Rulesets.Osu/OsuInputManager.cs @@ -6,10 +6,8 @@ using System.ComponentModel; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; -using osu.Framework.Input.StateChanges.Events; using osu.Game.Input.Bindings; using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.UI; From 45c5bd840310904dd36da949559777b8d4f66e69 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 14:37:09 +0900 Subject: [PATCH 188/376] Simplify HUD test to not require casting to specific `ProgressBar` type --- .../Visual/Gameplay/TestSceneHUDOverlay.cs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs index 713183ebaf..145f9380f8 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs @@ -213,17 +213,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("attempt seek", () => { - switch (getSongProgress()) - { - case SongProgressBar defaultBar: - InputManager.MoveMouseTo(defaultBar); - break; - - case ArgonSongProgressBar argonBar: - InputManager.MoveMouseTo(argonBar); - break; - } - + InputManager.MoveMouseTo(getSongProgress() as Drawable); InputManager.Click(MouseButton.Left); }); From afc12e0b835adf6eae3447a7b2ddb611d04462b4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 14:43:20 +0900 Subject: [PATCH 189/376] Tidy up `ISongProgressBar` interface --- osu.Game/Screens/Play/HUD/ISongProgressBar.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/ISongProgressBar.cs b/osu.Game/Screens/Play/HUD/ISongProgressBar.cs index f1a219e18b..683037577d 100644 --- a/osu.Game/Screens/Play/HUD/ISongProgressBar.cs +++ b/osu.Game/Screens/Play/HUD/ISongProgressBar.cs @@ -7,10 +7,14 @@ namespace osu.Game.Screens.Play.HUD { public interface ISongProgressBar { - public Action? OnSeek { get; set; } - public double StartTime { set; } - public double EndTime { set; } - public double CurrentTime { set; } + /// + /// Whether the progress bar should allow interaction, ie. to perform seek operations. + /// public bool Interactive { get; set; } + + /// + /// Action which is invoked when a seek is requested, with the proposed millisecond value for the seek operation. + /// + public Action? OnSeek { get; set; } } } From 5429979049c822167dec6c86f8be5d52a14dcb7d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 14:55:41 +0900 Subject: [PATCH 190/376] Combine common code into `SongProgress` base class --- .../Visual/Gameplay/TestSceneSongProgress.cs | 6 +-- .../Screens/Play/HUD/ArgonSongProgress.cs | 34 ++------------- .../Screens/Play/HUD/DefaultSongProgress.cs | 43 +++---------------- osu.Game/Screens/Play/HUD/SongProgress.cs | 31 ++++++++++--- osu.Game/Skinning/LegacySongProgress.cs | 14 ++---- 5 files changed, 40 insertions(+), 88 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs index 415a3c5b07..cecc24a807 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs @@ -54,10 +54,10 @@ namespace osu.Game.Tests.Visual.Gameplay void applyToDefaultProgress(Action action) => this.ChildrenOfType().ForEach(action); - AddStep("allow seeking", () => applyToDefaultProgress(s => s.AllowSeeking.Value = true)); + AddStep("allow seeking", () => applyToDefaultProgress(s => s.Interactive.Value = true)); AddStep("hide graph", () => applyToDefaultProgress(s => s.ShowGraph.Value = false)); - AddStep("disallow seeking", () => applyToDefaultProgress(s => s.AllowSeeking.Value = false)); - AddStep("allow seeking", () => applyToDefaultProgress(s => s.AllowSeeking.Value = true)); + AddStep("disallow seeking", () => applyToDefaultProgress(s => s.Interactive.Value = false)); + AddStep("allow seeking", () => applyToDefaultProgress(s => s.Interactive.Value = true)); AddStep("show graph", () => applyToDefaultProgress(s => s.ShowGraph.Value = true)); } diff --git a/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs b/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs index 8446abecd2..4951ad174b 100644 --- a/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs +++ b/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs @@ -3,11 +3,9 @@ using System.Collections.Generic; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Timing; -using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.UI; @@ -23,11 +21,6 @@ namespace osu.Game.Screens.Play.HUD private const float bar_height = 10; - public readonly Bindable AllowSeeking = new BindableBool(); - - [SettingSource("Show difficulty graph", "Whether a graph displaying difficulty throughout the beatmap should be shown")] - public Bindable ShowGraph { get; } = new BindableBool(true); - [Resolved] private DrawableRuleset? drawableRuleset { get; set; } @@ -80,14 +73,6 @@ namespace osu.Game.Screens.Play.HUD [BackgroundDependencyLoader] private void load() { - base.LoadComplete(); - - if (drawableRuleset != null) - { - if (player?.Configuration.AllowUserInteraction == true) - ((IBindable)AllowSeeking).BindTo(drawableRuleset.HasReplayLoaded); - } - info.ShowProgress = false; info.TextColour = Colour4.White; info.Font = OsuFont.Torus.With(size: 18, weight: FontWeight.Bold); @@ -95,7 +80,9 @@ namespace osu.Game.Screens.Play.HUD protected override void LoadComplete() { - AllowSeeking.BindValueChanged(_ => updateBarVisibility(), true); + base.LoadComplete(); + + Interactive.BindValueChanged(_ => bar.Interactive = Interactive.Value, true); ShowGraph.BindValueChanged(_ => updateGraphVisibility(), true); } @@ -107,11 +94,6 @@ namespace osu.Game.Screens.Play.HUD info.EndTime = bar.EndTime = LastHitTime; } - private void updateBarVisibility() - { - bar.Interactive = AllowSeeking.Value; - } - private void updateGraphVisibility() { graph.FadeTo(ShowGraph.Value ? 1 : 0, 200, Easing.In); @@ -125,16 +107,6 @@ namespace osu.Game.Screens.Play.HUD graphContainer.Height = bar.Height; } - protected override void PopIn() - { - this.FadeIn(500, Easing.OutQuint); - } - - protected override void PopOut() - { - this.FadeOut(100); - } - protected override void UpdateProgress(double progress, bool isIntro) { bar.ReferenceTime = GameplayClock.CurrentTime; diff --git a/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs b/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs index cb629a0b77..747f292e30 100644 --- a/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs +++ b/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs @@ -3,12 +3,9 @@ using System.Collections.Generic; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.UI; using osuTK; namespace osu.Game.Screens.Play.HUD @@ -27,23 +24,9 @@ namespace osu.Game.Screens.Play.HUD private readonly SongProgressGraph graph; private readonly SongProgressInfo info; - /// - /// Whether seeking is allowed and the progress bar should be shown. - /// - public readonly Bindable AllowSeeking = new Bindable(); - - [SettingSource("Show difficulty graph", "Whether a graph displaying difficulty throughout the beatmap should be shown")] - public Bindable ShowGraph { get; } = new BindableBool(true); - - public override bool HandleNonPositionalInput => AllowSeeking.Value; - public override bool HandlePositionalInput => AllowSeeking.Value; - [Resolved] private Player? player { get; set; } - [Resolved] - private DrawableRuleset? drawableRuleset { get; set; } - public DefaultSongProgress() { RelativeSizeAxes = Axes.X; @@ -75,34 +58,18 @@ namespace osu.Game.Screens.Play.HUD }; } - [BackgroundDependencyLoader(true)] + [BackgroundDependencyLoader] private void load(OsuColour colours) { - base.LoadComplete(); - - if (drawableRuleset != null) - { - if (player?.Configuration.AllowUserInteraction == true) - ((IBindable)AllowSeeking).BindTo(drawableRuleset.HasReplayLoaded); - } - graph.FillColour = bar.FillColour = colours.BlueLighter; } protected override void LoadComplete() { - AllowSeeking.BindValueChanged(_ => updateBarVisibility(), true); + Interactive.BindValueChanged(_ => updateBarVisibility(), true); ShowGraph.BindValueChanged(_ => updateGraphVisibility(), true); - } - protected override void PopIn() - { - this.FadeIn(500, Easing.OutQuint); - } - - protected override void PopOut() - { - this.FadeOut(100); + base.LoadComplete(); } protected override void UpdateObjects(IEnumerable objects) @@ -133,7 +100,7 @@ namespace osu.Game.Screens.Play.HUD private void updateBarVisibility() { - bar.Interactive = AllowSeeking.Value; + bar.Interactive = Interactive.Value; updateInfoMargin(); } @@ -150,7 +117,7 @@ namespace osu.Game.Screens.Play.HUD private void updateInfoMargin() { - float finalMargin = bottom_bar_height + (AllowSeeking.Value ? handle_size.Y : 0) + (ShowGraph.Value ? graph_height : 0); + float finalMargin = bottom_bar_height + (Interactive.Value ? handle_size.Y : 0) + (ShowGraph.Value ? graph_height : 0); info.TransformTo(nameof(info.Margin), new MarginPadding { Bottom = finalMargin }, transition_duration, Easing.In); } } diff --git a/osu.Game/Screens/Play/HUD/SongProgress.cs b/osu.Game/Screens/Play/HUD/SongProgress.cs index 4504745eb9..a708b07fc8 100644 --- a/osu.Game/Screens/Play/HUD/SongProgress.cs +++ b/osu.Game/Screens/Play/HUD/SongProgress.cs @@ -4,8 +4,11 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Timing; +using osu.Game.Configuration; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.UI; using osu.Game.Skinning; @@ -16,18 +19,27 @@ namespace osu.Game.Screens.Play.HUD { // Some implementations of this element allow seeking during gameplay playback. // Set a sane default of never handling input to override the behaviour provided by OverlayContainer. - public override bool HandleNonPositionalInput => false; - public override bool HandlePositionalInput => false; + public override bool HandleNonPositionalInput => Interactive.Value; + public override bool HandlePositionalInput => Interactive.Value; + protected override bool BlockScrollInput => false; + /// + /// Whether interaction should be allowed (ie. seeking). If false, interaction controls will not be displayed. + /// + /// + /// By default, this will be automatically decided based on the gameplay state. + /// + public readonly Bindable Interactive = new Bindable(); + + [SettingSource("Show difficulty graph", "Whether a graph displaying difficulty throughout the beatmap should be shown")] + public Bindable ShowGraph { get; } = new BindableBool(true); + public bool UsesFixedAnchor { get; set; } [Resolved] protected IGameplayClock GameplayClock { get; private set; } = null!; - [Resolved(canBeNull: true)] - private DrawableRuleset? drawableRuleset { get; set; } - private IClock? referenceClock; private IEnumerable? objects; @@ -58,15 +70,22 @@ namespace osu.Game.Screens.Play.HUD protected virtual void UpdateObjects(IEnumerable objects) { } [BackgroundDependencyLoader] - private void load() + private void load(DrawableRuleset? drawableRuleset, Player? player) { if (drawableRuleset != null) { + if (player?.Configuration.AllowUserInteraction == true) + ((IBindable)Interactive).BindTo(drawableRuleset.HasReplayLoaded); + Objects = drawableRuleset.Objects; referenceClock = drawableRuleset.FrameStableClock; } } + protected override void PopIn() => this.FadeIn(500, Easing.OutQuint); + + protected override void PopOut() => this.FadeOut(100); + protected override void Update() { base.Update(); diff --git a/osu.Game/Skinning/LegacySongProgress.cs b/osu.Game/Skinning/LegacySongProgress.cs index 10d1431ed4..22aea99291 100644 --- a/osu.Game/Skinning/LegacySongProgress.cs +++ b/osu.Game/Skinning/LegacySongProgress.cs @@ -15,6 +15,10 @@ namespace osu.Game.Skinning { private CircularProgress circularProgress = null!; + // Legacy song progress doesn't support interaction for now. + public override bool HandleNonPositionalInput => false; + public override bool HandlePositionalInput => false; + [BackgroundDependencyLoader] private void load() { @@ -56,16 +60,6 @@ namespace osu.Game.Skinning }; } - protected override void PopIn() - { - this.FadeIn(500, Easing.OutQuint); - } - - protected override void PopOut() - { - this.FadeOut(100); - } - protected override void UpdateProgress(double progress, bool isIntro) { if (isIntro) From f9dd3f6defcf56255338de446931cbaa1f39ecdc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 15:10:01 +0900 Subject: [PATCH 191/376] Switch test to specifically target the argon verison of the progress bar --- osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs index 145f9380f8..c7a4071d54 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs @@ -188,7 +188,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestInputDoesntWorkWhenHUDHidden() { - ISongProgressBar? getSongProgress() => hudOverlay.ChildrenOfType().SingleOrDefault(); + ArgonSongProgress? getSongProgress() => hudOverlay.ChildrenOfType().SingleOrDefault(); bool seeked = false; @@ -204,8 +204,8 @@ namespace osu.Game.Tests.Visual.Gameplay Debug.Assert(progress != null); - progress.Interactive = true; - progress.OnSeek += _ => seeked = true; + progress.Interactive.Value = true; + progress.ChildrenOfType().Single().OnSeek += _ => seeked = true; }); AddStep("set showhud false", () => hudOverlay.ShowHud.Value = false); From e8770b84cd2f81f6cf14aada7fa9f51e3ecf6d7c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 15:11:13 +0900 Subject: [PATCH 192/376] Remove no longer necessary interface type --- .../Visual/Gameplay/TestSceneHUDOverlay.cs | 2 +- .../TestSceneMultiSpectatorScreen.cs | 2 +- .../Screens/Play/HUD/ArgonSongProgressBar.cs | 2 +- osu.Game/Screens/Play/HUD/ISongProgressBar.cs | 20 ------------------- osu.Game/Screens/Play/HUD/SongProgressBar.cs | 20 ++++++++++++------- 5 files changed, 16 insertions(+), 30 deletions(-) delete mode 100644 osu.Game/Screens/Play/HUD/ISongProgressBar.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs index c7a4071d54..5e1412d79b 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs @@ -213,7 +213,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("attempt seek", () => { - InputManager.MoveMouseTo(getSongProgress() as Drawable); + InputManager.MoveMouseTo(getSongProgress()); InputManager.Click(MouseButton.Left); }); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index dd891b456c..e09496b6e9 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -121,7 +121,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("all interactive elements removed", () => this.ChildrenOfType().All(p => !p.ChildrenOfType().Any() && !p.ChildrenOfType().Any() && - p.ChildrenOfType().SingleOrDefault()?.Interactive == false)); + p.ChildrenOfType().SingleOrDefault()?.Interactive == false)); AddStep("restore config hud visibility", () => config.SetValue(OsuSetting.HUDVisibilityMode, originalConfigValue)); } diff --git a/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs b/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs index ff999aa6a3..a76b3d4b50 100644 --- a/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs +++ b/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs @@ -19,7 +19,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Play.HUD { - public partial class ArgonSongProgressBar : SliderBar, ISongProgressBar + public partial class ArgonSongProgressBar : SliderBar { private readonly float baseHeight; private readonly float catchupBaseDepth; diff --git a/osu.Game/Screens/Play/HUD/ISongProgressBar.cs b/osu.Game/Screens/Play/HUD/ISongProgressBar.cs deleted file mode 100644 index 683037577d..0000000000 --- a/osu.Game/Screens/Play/HUD/ISongProgressBar.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; - -namespace osu.Game.Screens.Play.HUD -{ - public interface ISongProgressBar - { - /// - /// Whether the progress bar should allow interaction, ie. to perform seek operations. - /// - public bool Interactive { get; set; } - - /// - /// Action which is invoked when a seek is requested, with the proposed millisecond value for the seek operation. - /// - public Action? OnSeek { get; set; } - } -} diff --git a/osu.Game/Screens/Play/HUD/SongProgressBar.cs b/osu.Game/Screens/Play/HUD/SongProgressBar.cs index fade562e3c..c2889d7e8a 100644 --- a/osu.Game/Screens/Play/HUD/SongProgressBar.cs +++ b/osu.Game/Screens/Play/HUD/SongProgressBar.cs @@ -13,16 +13,16 @@ using osu.Framework.Threading; namespace osu.Game.Screens.Play.HUD { - public partial class SongProgressBar : SliderBar, ISongProgressBar + public partial class SongProgressBar : SliderBar { + /// + /// Action which is invoked when a seek is requested, with the proposed millisecond value for the seek operation. + /// public Action? OnSeek { get; set; } - private readonly Box fill; - private readonly Container handleBase; - private readonly Container handleContainer; - - private bool showHandle; - + /// + /// Whether the progress bar should allow interaction, ie. to perform seek operations. + /// public bool Interactive { get => showHandle; @@ -57,6 +57,12 @@ namespace osu.Game.Screens.Play.HUD set => CurrentNumber.Value = value; } + private readonly Box fill; + private readonly Container handleBase; + private readonly Container handleContainer; + + private bool showHandle; + public SongProgressBar(float barHeight, float handleBarHeight, Vector2 handleSize) { CurrentNumber.MinValue = 0; From 742a02607710b79e1c34a61581919815e20befd4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 15:24:03 +0900 Subject: [PATCH 193/376] Add comment mentioning why reference clock fallback logic is required --- osu.Game/Screens/Play/HUD/ArgonSongProgress.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs b/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs index 4951ad174b..7f4123b094 100644 --- a/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs +++ b/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs @@ -24,6 +24,8 @@ namespace osu.Game.Screens.Play.HUD [Resolved] private DrawableRuleset? drawableRuleset { get; set; } + // Even though `FrameStabilityContainer` caches as a `GameplayClock`, we need to check it directly via `drawableRuleset` + // as this calculator is not contained within the `FrameStabilityContainer` and won't see the dependency. private IClock referenceClock => drawableRuleset?.FrameStableClock ?? GameplayClock; [Resolved] From 7266d8e10d49027dc8117824f793ab8dc7108ee4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 15:31:55 +0900 Subject: [PATCH 194/376] Move "show difficulty graph" settings back to respective implementations to avoid legacy version showing it --- osu.Game/Screens/Play/HUD/ArgonSongProgress.cs | 5 +++++ osu.Game/Screens/Play/HUD/DefaultSongProgress.cs | 5 +++++ osu.Game/Screens/Play/HUD/SongProgress.cs | 4 ---- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs b/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs index 7f4123b094..1290101138 100644 --- a/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs +++ b/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs @@ -3,9 +3,11 @@ using System.Collections.Generic; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Timing; +using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.UI; @@ -21,6 +23,9 @@ namespace osu.Game.Screens.Play.HUD private const float bar_height = 10; + [SettingSource("Show difficulty graph", "Whether a graph displaying difficulty throughout the beatmap should be shown")] + public Bindable ShowGraph { get; } = new BindableBool(true); + [Resolved] private DrawableRuleset? drawableRuleset { get; set; } diff --git a/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs b/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs index 747f292e30..a8bbe87e86 100644 --- a/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs +++ b/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs @@ -3,7 +3,9 @@ using System.Collections.Generic; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Rulesets.Objects; using osuTK; @@ -24,6 +26,9 @@ namespace osu.Game.Screens.Play.HUD private readonly SongProgressGraph graph; private readonly SongProgressInfo info; + [SettingSource("Show difficulty graph", "Whether a graph displaying difficulty throughout the beatmap should be shown")] + public Bindable ShowGraph { get; } = new BindableBool(true); + [Resolved] private Player? player { get; set; } diff --git a/osu.Game/Screens/Play/HUD/SongProgress.cs b/osu.Game/Screens/Play/HUD/SongProgress.cs index a708b07fc8..4ae79bda5d 100644 --- a/osu.Game/Screens/Play/HUD/SongProgress.cs +++ b/osu.Game/Screens/Play/HUD/SongProgress.cs @@ -8,7 +8,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Timing; -using osu.Game.Configuration; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.UI; using osu.Game.Skinning; @@ -32,9 +31,6 @@ namespace osu.Game.Screens.Play.HUD /// public readonly Bindable Interactive = new Bindable(); - [SettingSource("Show difficulty graph", "Whether a graph displaying difficulty throughout the beatmap should be shown")] - public Bindable ShowGraph { get; } = new BindableBool(true); - public bool UsesFixedAnchor { get; set; } [Resolved] From 1e5dd9165a270aca3a519124e4751912d38a5cb8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 15:37:46 +0900 Subject: [PATCH 195/376] Adjust `SkinnableTestScene` to give more breathing room to `RelativeSize` components --- osu.Game/Tests/Visual/SkinnableTestScene.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/osu.Game/Tests/Visual/SkinnableTestScene.cs b/osu.Game/Tests/Visual/SkinnableTestScene.cs index e8f51f9afa..aab1b72990 100644 --- a/osu.Game/Tests/Visual/SkinnableTestScene.cs +++ b/osu.Game/Tests/Visual/SkinnableTestScene.cs @@ -91,7 +91,7 @@ namespace osu.Game.Tests.Visual { RelativeSizeAxes = Axes.Both, BorderColour = Color4.White, - BorderThickness = 5, + BorderThickness = 3, Masking = true, Children = new Drawable[] @@ -142,8 +142,15 @@ namespace osu.Game.Tests.Visual c.AutoSizeAxes = Axes.None; c.Size = Vector2.Zero; - c.RelativeSizeAxes = !autoSize ? Axes.Both : Axes.None; - c.AutoSizeAxes = autoSize ? Axes.Both : Axes.None; + if (autoSize) + c.AutoSizeAxes = Axes.Both; + else + { + c.RelativeSizeAxes = Axes.Both; + c.Anchor = Anchor.Centre; + c.Origin = Anchor.Centre; + c.Size = new Vector2(0.97f); + } } outlineBox.Alpha = autoSize ? 1 : 0; From 04c0a5d7283ff1185349e30666893e0e9cc71708 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 15:44:19 +0900 Subject: [PATCH 196/376] Update `TestSceneSongProgress` to properly work with new implementation --- .../Visual/Gameplay/TestSceneSongProgress.cs | 39 ++++++++++++------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs index cecc24a807..bd6a42f9c0 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; @@ -38,28 +39,38 @@ namespace osu.Game.Tests.Visual.Gameplay { AddStep("reset clock", () => gameplayClockContainer.Reset()); AddStep("set hit objects", setHitObjects); + AddStep("hook seeking", () => + { + applyToDefaultProgress(d => d.ChildrenOfType().Single().OnSeek += t => gameplayClockContainer.Seek(t)); + applyToArgonProgress(d => d.ChildrenOfType().Single().OnSeek += t => gameplayClockContainer.Seek(t)); + }); + AddStep("seek to intro", () => gameplayClockContainer.Seek(skip_target_time)); + AddStep("start", gameplayClockContainer.Start); } [Test] - public void TestDisplay() + public void TestBasic() { - AddStep("seek to intro", () => gameplayClockContainer.Seek(skip_target_time)); - AddStep("start", gameplayClockContainer.Start); + AddToggleStep("toggle seeking", b => + { + applyToDefaultProgress(s => s.Interactive.Value = b); + applyToArgonProgress(s => s.Interactive.Value = b); + }); + + AddToggleStep("toggle graph", b => + { + applyToDefaultProgress(s => s.ShowGraph.Value = b); + applyToArgonProgress(s => s.ShowGraph.Value = b); + }); + AddStep("stop", gameplayClockContainer.Stop); } - [Test] - public void TestToggleSeeking() - { - void applyToDefaultProgress(Action action) => - this.ChildrenOfType().ForEach(action); + private void applyToArgonProgress(Action action) => + this.ChildrenOfType().ForEach(action); - AddStep("allow seeking", () => applyToDefaultProgress(s => s.Interactive.Value = true)); - AddStep("hide graph", () => applyToDefaultProgress(s => s.ShowGraph.Value = false)); - AddStep("disallow seeking", () => applyToDefaultProgress(s => s.Interactive.Value = false)); - AddStep("allow seeking", () => applyToDefaultProgress(s => s.Interactive.Value = true)); - AddStep("show graph", () => applyToDefaultProgress(s => s.ShowGraph.Value = true)); - } + private void applyToDefaultProgress(Action action) => + this.ChildrenOfType().ForEach(action); private void setHitObjects() { From bfb75730a99da5543172053741c3872aea813e87 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 15:45:16 +0900 Subject: [PATCH 197/376] Prefix subclasses of `DefaultSongProgress` with `Default` --- ...gressGraph.cs => TestSceneDefaultSongProgressGraph.cs} | 4 ++-- osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs | 2 +- osu.Game/Screens/Play/HUD/DefaultSongProgress.cs | 8 ++++---- .../HUD/{SongProgressBar.cs => DefaultSongProgressBar.cs} | 4 ++-- .../{SongProgressGraph.cs => DefaultSongProgressGraph.cs} | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) rename osu.Game.Tests/Visual/Gameplay/{TestSceneSongProgressGraph.cs => TestSceneDefaultSongProgressGraph.cs} (93%) rename osu.Game/Screens/Play/HUD/{SongProgressBar.cs => DefaultSongProgressBar.cs} (96%) rename osu.Game/Screens/Play/HUD/{SongProgressGraph.cs => DefaultSongProgressGraph.cs} (95%) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgressGraph.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDefaultSongProgressGraph.cs similarity index 93% rename from osu.Game.Tests/Visual/Gameplay/TestSceneSongProgressGraph.cs rename to osu.Game.Tests/Visual/Gameplay/TestSceneDefaultSongProgressGraph.cs index 5a61502978..66671a506f 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgressGraph.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDefaultSongProgressGraph.cs @@ -14,7 +14,7 @@ using osu.Game.Screens.Play.HUD; namespace osu.Game.Tests.Visual.Gameplay { [TestFixture] - public partial class TestSceneSongProgressGraph : OsuTestScene + public partial class TestSceneDefaultSongProgressGraph : OsuTestScene { private TestSongProgressGraph graph; @@ -59,7 +59,7 @@ namespace osu.Game.Tests.Visual.Gameplay graph.Objects = objects; } - private partial class TestSongProgressGraph : SongProgressGraph + private partial class TestSongProgressGraph : DefaultSongProgressGraph { public int CreationCount { get; private set; } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs index bd6a42f9c0..61b15c092b 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs @@ -41,7 +41,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("set hit objects", setHitObjects); AddStep("hook seeking", () => { - applyToDefaultProgress(d => d.ChildrenOfType().Single().OnSeek += t => gameplayClockContainer.Seek(t)); + applyToDefaultProgress(d => d.ChildrenOfType().Single().OnSeek += t => gameplayClockContainer.Seek(t)); applyToArgonProgress(d => d.ChildrenOfType().Single().OnSeek += t => gameplayClockContainer.Seek(t)); }); AddStep("seek to intro", () => gameplayClockContainer.Seek(skip_target_time)); diff --git a/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs b/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs index a8bbe87e86..91a34fe374 100644 --- a/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs +++ b/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs @@ -22,8 +22,8 @@ namespace osu.Game.Screens.Play.HUD private const float transition_duration = 200; - private readonly SongProgressBar bar; - private readonly SongProgressGraph graph; + private readonly DefaultSongProgressBar bar; + private readonly DefaultSongProgressGraph graph; private readonly SongProgressInfo info; [SettingSource("Show difficulty graph", "Whether a graph displaying difficulty throughout the beatmap should be shown")] @@ -46,7 +46,7 @@ namespace osu.Game.Screens.Play.HUD Anchor = Anchor.BottomLeft, RelativeSizeAxes = Axes.X, }, - graph = new SongProgressGraph + graph = new DefaultSongProgressGraph { RelativeSizeAxes = Axes.X, Origin = Anchor.BottomLeft, @@ -54,7 +54,7 @@ namespace osu.Game.Screens.Play.HUD Height = graph_height, Margin = new MarginPadding { Bottom = bottom_bar_height }, }, - bar = new SongProgressBar(bottom_bar_height, graph_height, handle_size) + bar = new DefaultSongProgressBar(bottom_bar_height, graph_height, handle_size) { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, diff --git a/osu.Game/Screens/Play/HUD/SongProgressBar.cs b/osu.Game/Screens/Play/HUD/DefaultSongProgressBar.cs similarity index 96% rename from osu.Game/Screens/Play/HUD/SongProgressBar.cs rename to osu.Game/Screens/Play/HUD/DefaultSongProgressBar.cs index c2889d7e8a..0e16067dcc 100644 --- a/osu.Game/Screens/Play/HUD/SongProgressBar.cs +++ b/osu.Game/Screens/Play/HUD/DefaultSongProgressBar.cs @@ -13,7 +13,7 @@ using osu.Framework.Threading; namespace osu.Game.Screens.Play.HUD { - public partial class SongProgressBar : SliderBar + public partial class DefaultSongProgressBar : SliderBar { /// /// Action which is invoked when a seek is requested, with the proposed millisecond value for the seek operation. @@ -63,7 +63,7 @@ namespace osu.Game.Screens.Play.HUD private bool showHandle; - public SongProgressBar(float barHeight, float handleBarHeight, Vector2 handleSize) + public DefaultSongProgressBar(float barHeight, float handleBarHeight, Vector2 handleSize) { CurrentNumber.MinValue = 0; CurrentNumber.MaxValue = 1; diff --git a/osu.Game/Screens/Play/HUD/SongProgressGraph.cs b/osu.Game/Screens/Play/HUD/DefaultSongProgressGraph.cs similarity index 95% rename from osu.Game/Screens/Play/HUD/SongProgressGraph.cs rename to osu.Game/Screens/Play/HUD/DefaultSongProgressGraph.cs index f69a1eccd6..bee5978817 100644 --- a/osu.Game/Screens/Play/HUD/SongProgressGraph.cs +++ b/osu.Game/Screens/Play/HUD/DefaultSongProgressGraph.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Objects; namespace osu.Game.Screens.Play.HUD { - public partial class SongProgressGraph : SquareGraph + public partial class DefaultSongProgressGraph : SquareGraph { private IEnumerable objects; From 8bfd8538897aa288af5a15663c817bff2a4216e7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 16:04:14 +0900 Subject: [PATCH 198/376] Fix missing comment --- osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs b/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs index a76b3d4b50..7483d9cb51 100644 --- a/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs +++ b/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs @@ -173,7 +173,7 @@ namespace osu.Game.Screens.Play.HUD protected override void UpdateValue(float value) { - // + // Handled in Update } protected override void Update() From 8030194cd58fddf5b30e90597d339684f509f1f2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 16:04:07 +0900 Subject: [PATCH 199/376] Use actual beatmap's hitobjects in test to better display density --- .../Visual/Gameplay/TestSceneSongProgress.cs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs index 61b15c092b..561d34285b 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs @@ -2,14 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Testing; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu; using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; @@ -38,7 +36,7 @@ namespace osu.Game.Tests.Visual.Gameplay public void SetupSteps() { AddStep("reset clock", () => gameplayClockContainer.Reset()); - AddStep("set hit objects", setHitObjects); + AddStep("set hit objects", () => this.ChildrenOfType().ForEach(progress => progress.Objects = Beatmap.Value.Beatmap.HitObjects)); AddStep("hook seeking", () => { applyToDefaultProgress(d => d.ChildrenOfType().Single().OnSeek += t => gameplayClockContainer.Seek(t)); @@ -72,15 +70,6 @@ namespace osu.Game.Tests.Visual.Gameplay private void applyToDefaultProgress(Action action) => this.ChildrenOfType().ForEach(action); - private void setHitObjects() - { - var objects = new List(); - for (double i = 0; i < 5000; i++) - objects.Add(new HitObject { StartTime = i }); - - this.ChildrenOfType().ForEach(progress => progress.Objects = objects); - } - protected override Drawable CreateDefaultImplementation() => new DefaultSongProgress(); protected override Drawable CreateArgonImplementation() => new ArgonSongProgress(); From 5ead85f461eb99775896d09f3931005e0857d030 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 16:13:43 +0900 Subject: [PATCH 200/376] Limit catch-up speed in test to emulate gameplay --- .../Visual/Gameplay/TestSceneSongProgress.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs index 561d34285b..05e0c05b61 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs @@ -9,6 +9,7 @@ using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.UI; using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; using osu.Game.Skinning; @@ -27,9 +28,17 @@ namespace osu.Game.Tests.Visual.Gameplay { Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo); - Add(gameplayClockContainer = new MasterGameplayClockContainer(Beatmap.Value, skip_target_time)); + FrameStabilityContainer frameStabilityContainer; - Dependencies.CacheAs(gameplayClockContainer); + Add(gameplayClockContainer = new MasterGameplayClockContainer(Beatmap.Value, skip_target_time) + { + Child = frameStabilityContainer = new FrameStabilityContainer + { + MaxCatchUpFrames = 1 + } + }); + + Dependencies.CacheAs(frameStabilityContainer); } [SetUpSteps] From 42e9b2b48cd8031ba9a75933845a09be14127ae9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 16:29:42 +0900 Subject: [PATCH 201/376] Tidy up clock logic in all `SongProgress` classes --- .../Visual/Gameplay/TestSceneSongProgress.cs | 3 ++- .../Screens/Play/HUD/ArgonSongProgress.cs | 13 ++--------- .../Screens/Play/HUD/ArgonSongProgressBar.cs | 22 +++++++++---------- .../ClicksPerSecondCalculator.cs | 8 +++---- osu.Game/Screens/Play/HUD/SongProgress.cs | 15 ++++++++----- osu.Game/Screens/Play/Player.cs | 1 + 6 files changed, 29 insertions(+), 33 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs index 05e0c05b61..76cd1b56d7 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs @@ -38,7 +38,8 @@ namespace osu.Game.Tests.Visual.Gameplay } }); - Dependencies.CacheAs(frameStabilityContainer); + Dependencies.CacheAs(gameplayClockContainer); + Dependencies.CacheAs(frameStabilityContainer); } [SetUpSteps] diff --git a/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs b/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs index 1290101138..3a2cd6fe2a 100644 --- a/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs +++ b/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs @@ -6,11 +6,9 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Timing; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.UI; namespace osu.Game.Screens.Play.HUD { @@ -26,13 +24,6 @@ namespace osu.Game.Screens.Play.HUD [SettingSource("Show difficulty graph", "Whether a graph displaying difficulty throughout the beatmap should be shown")] public Bindable ShowGraph { get; } = new BindableBool(true); - [Resolved] - private DrawableRuleset? drawableRuleset { get; set; } - - // Even though `FrameStabilityContainer` caches as a `GameplayClock`, we need to check it directly via `drawableRuleset` - // as this calculator is not contained within the `FrameStabilityContainer` and won't see the dependency. - private IClock referenceClock => drawableRuleset?.FrameStableClock ?? GameplayClock; - [Resolved] private Player? player { get; set; } @@ -116,12 +107,12 @@ namespace osu.Game.Screens.Play.HUD protected override void UpdateProgress(double progress, bool isIntro) { - bar.ReferenceTime = GameplayClock.CurrentTime; + bar.TrackTime = GameplayClock.CurrentTime; if (isIntro) bar.CurrentTime = 0; else - bar.CurrentTime = referenceClock.CurrentTime; + bar.CurrentTime = FrameStableClock.CurrentTime; } } } diff --git a/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs b/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs index 7483d9cb51..f69d56873d 100644 --- a/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs +++ b/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs @@ -64,21 +64,21 @@ namespace osu.Game.Screens.Play.HUD set => CurrentNumber.Value = value; } - public double ReferenceTime + public double TrackTime { - private get => currentReference.Value; - set => currentReference.Value = value; + private get => currentTrackTime.Value; + set => currentTrackTime.Value = value; } private double length => EndTime - StartTime; - private readonly BindableNumber currentReference; + private readonly BindableNumber currentTrackTime; public bool Interactive { get; set; } public ArgonSongProgressBar(float barHeight) { - currentReference = new BindableDouble(); + currentTrackTime = new BindableDouble(); setupAlternateValue(); StartTime = 0; @@ -124,9 +124,9 @@ namespace osu.Game.Screens.Play.HUD private void setupAlternateValue() { - CurrentNumber.MaxValueChanged += v => currentReference.MaxValue = v; - CurrentNumber.MinValueChanged += v => currentReference.MinValue = v; - CurrentNumber.PrecisionChanged += v => currentReference.Precision = v; + CurrentNumber.MaxValueChanged += v => currentTrackTime.MaxValue = v; + CurrentNumber.MinValueChanged += v => currentTrackTime.MinValue = v; + CurrentNumber.PrecisionChanged += v => currentTrackTime.Precision = v; } private float normalizedReference @@ -136,7 +136,7 @@ namespace osu.Game.Screens.Play.HUD if (EndTime - StartTime == 0) return 1; - return (float)((ReferenceTime - StartTime) / length); + return (float)((TrackTime - StartTime) / length); } } @@ -183,12 +183,12 @@ namespace osu.Game.Screens.Play.HUD playfieldBar.Length = (float)Interpolation.Lerp(playfieldBar.Length, NormalizedValue, Math.Clamp(Time.Elapsed / 40, 0, 1)); catchupBar.Length = (float)Interpolation.Lerp(catchupBar.Length, normalizedReference, Math.Clamp(Time.Elapsed / 40, 0, 1)); - if (ReferenceTime < CurrentTime) + if (TrackTime < CurrentTime) ChangeChildDepth(catchupBar, playfieldBar.Depth - 0.1f); else ChangeChildDepth(catchupBar, catchupBaseDepth); - float timeDelta = (float)(Math.Abs(CurrentTime - ReferenceTime)); + float timeDelta = (float)(Math.Abs(CurrentTime - TrackTime)); catchupBar.Alpha = MathHelper.Clamp(timeDelta, 0, alpha_threshold) / alpha_threshold; } diff --git a/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs index bf1f508d7b..ba0c47dc8b 100644 --- a/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs +++ b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs @@ -15,14 +15,12 @@ namespace osu.Game.Screens.Play.HUD.ClicksPerSecond [Resolved] private IGameplayClock gameplayClock { get; set; } = null!; - [Resolved(canBeNull: true)] - private DrawableRuleset? drawableRuleset { get; set; } + [Resolved] + private IFrameStableClock? frameStableClock { get; set; } public int Value { get; private set; } - // Even though `FrameStabilityContainer` caches as a `GameplayClock`, we need to check it directly via `drawableRuleset` - // as this calculator is not contained within the `FrameStabilityContainer` and won't see the dependency. - private IGameplayClock clock => drawableRuleset?.FrameStableClock ?? gameplayClock; + private IGameplayClock clock => frameStableClock ?? gameplayClock; public ClicksPerSecondCalculator() { diff --git a/osu.Game/Screens/Play/HUD/SongProgress.cs b/osu.Game/Screens/Play/HUD/SongProgress.cs index 4ae79bda5d..4647c0352b 100644 --- a/osu.Game/Screens/Play/HUD/SongProgress.cs +++ b/osu.Game/Screens/Play/HUD/SongProgress.cs @@ -36,7 +36,15 @@ namespace osu.Game.Screens.Play.HUD [Resolved] protected IGameplayClock GameplayClock { get; private set; } = null!; - private IClock? referenceClock; + [Resolved] + private IFrameStableClock? frameStableClock { get; set; } + + /// + /// The reference clock is used to accurately tell the current playfield's time (including catch-up lag). + /// However, if none is available (i.e. used in tests), we fall back to the gameplay clock. + /// + protected IClock FrameStableClock => frameStableClock ?? GameplayClock; + private IEnumerable? objects; public IEnumerable Objects @@ -74,7 +82,6 @@ namespace osu.Game.Screens.Play.HUD ((IBindable)Interactive).BindTo(drawableRuleset.HasReplayLoaded); Objects = drawableRuleset.Objects; - referenceClock = drawableRuleset.FrameStableClock; } } @@ -89,9 +96,7 @@ namespace osu.Game.Screens.Play.HUD if (objects == null) return; - // The reference clock is used to accurately tell the playfield's time. This is obtained from the drawable ruleset. - // However, if no drawable ruleset is available (i.e. used in tests), we fall back to the gameplay clock. - double currentTime = referenceClock?.CurrentTime ?? GameplayClock.CurrentTime; + double currentTime = FrameStableClock.CurrentTime; bool isInIntro = currentTime < FirstHitTime; diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 05133fba35..d3ab936a38 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -225,6 +225,7 @@ namespace osu.Game.Screens.Play DrawableRuleset = ruleset.CreateDrawableRulesetWith(playableBeatmap, gameplayMods); dependencies.CacheAs(DrawableRuleset); + dependencies.CacheAs(DrawableRuleset.FrameStableClock); ScoreProcessor = ruleset.CreateScoreProcessor(); ScoreProcessor.Mods.Value = gameplayMods; From 7d0388c55cc9d1131a7a6ba92a73ec72aacc8795 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 16:29:42 +0900 Subject: [PATCH 202/376] Cache `IFrameStableClock` in `Player` for easier access Allows directly referencing rather than going through `DrawableRuleset`. Helps with testing and implementation of the new song progress display (#22144). --- .../ClicksPerSecondCalculator.cs | 8 +++----- osu.Game/Screens/Play/HUD/SongProgress.cs | 18 ++++++++++-------- osu.Game/Screens/Play/Player.cs | 1 + 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs index bf1f508d7b..ba0c47dc8b 100644 --- a/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs +++ b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs @@ -15,14 +15,12 @@ namespace osu.Game.Screens.Play.HUD.ClicksPerSecond [Resolved] private IGameplayClock gameplayClock { get; set; } = null!; - [Resolved(canBeNull: true)] - private DrawableRuleset? drawableRuleset { get; set; } + [Resolved] + private IFrameStableClock? frameStableClock { get; set; } public int Value { get; private set; } - // Even though `FrameStabilityContainer` caches as a `GameplayClock`, we need to check it directly via `drawableRuleset` - // as this calculator is not contained within the `FrameStabilityContainer` and won't see the dependency. - private IGameplayClock clock => drawableRuleset?.FrameStableClock ?? gameplayClock; + private IGameplayClock clock => frameStableClock ?? gameplayClock; public ClicksPerSecondCalculator() { diff --git a/osu.Game/Screens/Play/HUD/SongProgress.cs b/osu.Game/Screens/Play/HUD/SongProgress.cs index 4504745eb9..c5f5de6f48 100644 --- a/osu.Game/Screens/Play/HUD/SongProgress.cs +++ b/osu.Game/Screens/Play/HUD/SongProgress.cs @@ -25,10 +25,15 @@ namespace osu.Game.Screens.Play.HUD [Resolved] protected IGameplayClock GameplayClock { get; private set; } = null!; - [Resolved(canBeNull: true)] - private DrawableRuleset? drawableRuleset { get; set; } + [Resolved] + private IFrameStableClock? frameStableClock { get; set; } + + /// + /// The reference clock is used to accurately tell the current playfield's time (including catch-up lag). + /// However, if none is available (i.e. used in tests), we fall back to the gameplay clock. + /// + protected IClock FrameStableClock => frameStableClock ?? GameplayClock; - private IClock? referenceClock; private IEnumerable? objects; public IEnumerable Objects @@ -58,12 +63,11 @@ namespace osu.Game.Screens.Play.HUD protected virtual void UpdateObjects(IEnumerable objects) { } [BackgroundDependencyLoader] - private void load() + private void load(DrawableRuleset? drawableRuleset) { if (drawableRuleset != null) { Objects = drawableRuleset.Objects; - referenceClock = drawableRuleset.FrameStableClock; } } @@ -74,9 +78,7 @@ namespace osu.Game.Screens.Play.HUD if (objects == null) return; - // The reference clock is used to accurately tell the playfield's time. This is obtained from the drawable ruleset. - // However, if no drawable ruleset is available (i.e. used in tests), we fall back to the gameplay clock. - double currentTime = referenceClock?.CurrentTime ?? GameplayClock.CurrentTime; + double currentTime = FrameStableClock.CurrentTime; bool isInIntro = currentTime < FirstHitTime; diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 05133fba35..d3ab936a38 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -225,6 +225,7 @@ namespace osu.Game.Screens.Play DrawableRuleset = ruleset.CreateDrawableRulesetWith(playableBeatmap, gameplayMods); dependencies.CacheAs(DrawableRuleset); + dependencies.CacheAs(DrawableRuleset.FrameStableClock); ScoreProcessor = ruleset.CreateScoreProcessor(); ScoreProcessor.Mods.Value = gameplayMods; From f3677ab33dde950ef65d742b9a0169cbc17d6bb1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 16:38:21 +0900 Subject: [PATCH 203/376] Simplify depth change logic --- osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs b/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs index f69d56873d..43969f2593 100644 --- a/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs +++ b/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs @@ -22,7 +22,6 @@ namespace osu.Game.Screens.Play.HUD public partial class ArgonSongProgressBar : SliderBar { private readonly float baseHeight; - private readonly float catchupBaseDepth; private readonly RoundedBar playfieldBar; private readonly RoundedBar catchupBar; @@ -118,7 +117,7 @@ namespace osu.Game.Screens.Play.HUD RelativeSizeAxes = Axes.Both }, }; - catchupBaseDepth = catchupBar.Depth; + mainColourDarkened = Colour4.White.Darken(1 / 3f); } @@ -184,9 +183,9 @@ namespace osu.Game.Screens.Play.HUD catchupBar.Length = (float)Interpolation.Lerp(catchupBar.Length, normalizedReference, Math.Clamp(Time.Elapsed / 40, 0, 1)); if (TrackTime < CurrentTime) - ChangeChildDepth(catchupBar, playfieldBar.Depth - 0.1f); + ChangeChildDepth(catchupBar, -1); else - ChangeChildDepth(catchupBar, catchupBaseDepth); + ChangeChildDepth(catchupBar, 0); float timeDelta = (float)(Math.Abs(CurrentTime - TrackTime)); catchupBar.Alpha = MathHelper.Clamp(timeDelta, 0, alpha_threshold) / alpha_threshold; From 01558a919952c0965c4661b6f538ceae1fe2d3c2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 16:56:07 +0900 Subject: [PATCH 204/376] Tidy up height logic and allow hovering above bar for easier interaction --- .../Screens/Play/HUD/ArgonSongProgressBar.cs | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs b/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs index 43969f2593..028ba7e35b 100644 --- a/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs +++ b/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs @@ -4,7 +4,6 @@ using System; 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; @@ -21,7 +20,12 @@ namespace osu.Game.Screens.Play.HUD { public partial class ArgonSongProgressBar : SliderBar { - private readonly float baseHeight; + public Action? OnSeek { get; set; } + + // Parent will handle restricting the area of valid input. + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; + + private readonly float barHeight; private readonly RoundedBar playfieldBar; private readonly RoundedBar catchupBar; @@ -32,8 +36,8 @@ namespace osu.Game.Screens.Play.HUD private readonly ColourInfo mainColour; private readonly ColourInfo mainColourDarkened; - private ColourInfo altColour; - private ColourInfo altColourDarkened; + private ColourInfo catchUpColour; + private ColourInfo catchUpColourDarkened; public bool ShowBackground { @@ -43,8 +47,6 @@ namespace osu.Game.Screens.Play.HUD private const float alpha_threshold = 2500; - public Action? OnSeek { get; set; } - public double StartTime { private get => CurrentNumber.MinValue; @@ -84,8 +86,7 @@ namespace osu.Game.Screens.Play.HUD EndTime = 1; RelativeSizeAxes = Axes.X; - baseHeight = barHeight; - Height = baseHeight; + Height = this.barHeight = barHeight; CornerRadius = 5; Masking = true; @@ -142,31 +143,30 @@ namespace osu.Game.Screens.Play.HUD [BackgroundDependencyLoader] private void load(OsuColour colours) { - catchupBar.AccentColour = altColour = colours.BlueLight; - altColourDarkened = colours.BlueLight.Darken(1 / 3f); + catchUpColour = colours.BlueLight; + catchUpColourDarkened = colours.BlueDark; + showBackground.BindValueChanged(_ => updateBackground(), true); } private void updateBackground() { background.FadeTo(showBackground.Value ? 1 / 4f : 0, 200, Easing.In); - catchupBar.TransformTo(nameof(catchupBar.AccentColour), ShowBackground ? altColour : altColourDarkened, 200, Easing.In); + catchupBar.TransformTo(nameof(catchupBar.AccentColour), ShowBackground ? catchUpColour : catchUpColourDarkened, 200, Easing.In); playfieldBar.TransformTo(nameof(playfieldBar.AccentColour), ShowBackground ? mainColour : mainColourDarkened, 200, Easing.In); } protected override bool OnHover(HoverEvent e) { if (Interactive) - this.ResizeHeightTo(baseHeight * 3.5f, 200, Easing.Out); + this.ResizeHeightTo(barHeight * 3.5f, 200, Easing.Out); return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { - if (Interactive) - this.ResizeHeightTo(baseHeight, 200, Easing.In); - + this.ResizeHeightTo(barHeight, 800, Easing.OutQuint); base.OnHoverLost(e); } From 67b40dd2343d279ac13b11b8f5c090e2a9fd1326 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 17:09:39 +0900 Subject: [PATCH 205/376] Adjust the seek effect to feel better --- osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs b/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs index 028ba7e35b..6db1072fbb 100644 --- a/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs +++ b/osu.Game/Screens/Play/HUD/ArgonSongProgressBar.cs @@ -45,8 +45,6 @@ namespace osu.Game.Screens.Play.HUD set => showBackground.Value = value; } - private const float alpha_threshold = 2500; - public double StartTime { private get => CurrentNumber.MinValue; @@ -152,7 +150,6 @@ namespace osu.Game.Screens.Play.HUD private void updateBackground() { background.FadeTo(showBackground.Value ? 1 / 4f : 0, 200, Easing.In); - catchupBar.TransformTo(nameof(catchupBar.AccentColour), ShowBackground ? catchUpColour : catchUpColourDarkened, 200, Easing.In); playfieldBar.TransformTo(nameof(playfieldBar.AccentColour), ShowBackground ? mainColour : mainColourDarkened, 200, Easing.In); } @@ -188,7 +185,17 @@ namespace osu.Game.Screens.Play.HUD ChangeChildDepth(catchupBar, 0); float timeDelta = (float)(Math.Abs(CurrentTime - TrackTime)); - catchupBar.Alpha = MathHelper.Clamp(timeDelta, 0, alpha_threshold) / alpha_threshold; + + const float colour_transition_threshold = 20000; + + catchupBar.AccentColour = Interpolation.ValueAt( + Math.Min(timeDelta, colour_transition_threshold), + ShowBackground ? mainColour : mainColourDarkened, + ShowBackground ? catchUpColour : catchUpColourDarkened, + 0, colour_transition_threshold, + Easing.OutQuint); + + catchupBar.Alpha = Math.Max(1, catchupBar.Length); } private ScheduledDelegate? scheduledSeek; From 04705504c583de28139af134ae8d00d194c104a3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 17:19:57 +0900 Subject: [PATCH 206/376] Move cache to more appropriate location --- osu.Game/Screens/Play/Player.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index d3ab936a38..77c16718f5 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -225,7 +225,6 @@ namespace osu.Game.Screens.Play DrawableRuleset = ruleset.CreateDrawableRulesetWith(playableBeatmap, gameplayMods); dependencies.CacheAs(DrawableRuleset); - dependencies.CacheAs(DrawableRuleset.FrameStableClock); ScoreProcessor = ruleset.CreateScoreProcessor(); ScoreProcessor.Mods.Value = gameplayMods; @@ -310,6 +309,8 @@ namespace osu.Game.Screens.Play }); } + dependencies.CacheAs(DrawableRuleset.FrameStableClock); + // add the overlay components as a separate step as they proxy some elements from the above underlay/gameplay components. // also give the overlays the ruleset skin provider to allow rulesets to potentially override HUD elements (used to disable combo counters etc.) // we may want to limit this in the future to disallow rulesets from outright replacing elements the user expects to be there. From ecb4727aeca1d1011a793ccab2b85f8f67bc6dc8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 17:33:14 +0900 Subject: [PATCH 207/376] 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 208/376] 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 d4f2cd244db510f7d0096ad514e5af6214ad2067 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 18:12:40 +0900 Subject: [PATCH 209/376] Fix broken test step --- osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs index 76cd1b56d7..5855838d3c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs @@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.Gameplay applyToArgonProgress(d => d.ChildrenOfType().Single().OnSeek += t => gameplayClockContainer.Seek(t)); }); AddStep("seek to intro", () => gameplayClockContainer.Seek(skip_target_time)); - AddStep("start", gameplayClockContainer.Start); + AddStep("start", () => gameplayClockContainer.Start()); } [Test] From 4ef940653bad6fb9097d59401cacc53a417488d6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 19:03:03 +0900 Subject: [PATCH 210/376] Fix legacy judgement animation not matching perfectly This will be the final attempt to get it right. I was seemingly drunk last time I wrote the logic. Closes #21892. --- osu.Game/Skinning/LegacyJudgementPieceOld.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/osu.Game/Skinning/LegacyJudgementPieceOld.cs b/osu.Game/Skinning/LegacyJudgementPieceOld.cs index 0223e7a5a2..796080f4f5 100644 --- a/osu.Game/Skinning/LegacyJudgementPieceOld.cs +++ b/osu.Game/Skinning/LegacyJudgementPieceOld.cs @@ -65,11 +65,14 @@ namespace osu.Game.Skinning default: this.ScaleTo(0.6f).Then() - .ScaleTo(1.1f, fade_in_length * 0.8f).Then() - // this is actually correct to match stable; there were overlapping transforms. - .ScaleTo(0.9f).Delay(fade_in_length * 0.2f) - .ScaleTo(1.1f).ScaleTo(0.9f, fade_in_length * 0.2f).Then() - .ScaleTo(0.95f).ScaleTo(finalScale, fade_in_length * 0.2f); + .ScaleTo(1.1f, fade_in_length * 0.8f).Then() // t = 0.8 + .Delay(fade_in_length * 0.2f) // t = 1.0 + .ScaleTo(0.9f, fade_in_length * 0.2f).Then() // t = 1.2 + + // stable dictates scale of 0.9->1 over time 1.0 to 1.4, but we are already at 1.2. + // so we need to force the current value to be correct at 1.2 (0.95) then complete the + // second half of the transform. + .ScaleTo(0.95f).ScaleTo(finalScale, fade_in_length * 0.2f); // t = 1.4 break; } } From 3b27774561c054b3234c82341c070fb581e4b9b4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 19:13:26 +0900 Subject: [PATCH 211/376] Remove `OnlineID` sort consideration --- .../SongSelect/TestSceneBeatmapCarousel.cs | 88 ++++--------------- .../Select/Carousel/CarouselBeatmapSet.cs | 8 +- 2 files changed, 20 insertions(+), 76 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index e658d87497..65ce0429fc 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -613,50 +613,6 @@ namespace osu.Game.Tests.Visual.SongSelect AddAssert("Items remain in descending added order", () => carousel.BeatmapSets.Select(s => s.DateAdded), () => Is.Ordered.Descending); } - /// - /// Ensures stability is maintained on different sort modes for items with equal properties. - /// - [Test] - public void TestSortingStabilityOnlineID() - { - var sets = new List(); - int idOffset = 0; - - AddStep("Populuate beatmap sets", () => - { - sets.Clear(); - - for (int i = 0; i < 10; i++) - { - var set = TestResources.CreateTestBeatmapSetInfo(); - - // only need to set the first as they are a shared reference. - var beatmap = set.Beatmaps.First(); - - beatmap.Metadata.Artist = $"artist {i / 2}"; - beatmap.Metadata.Title = $"title {9 - i}"; - - // testing the case where DateAdded happens to equal (quite rare). - set.DateAdded = DateTimeOffset.UnixEpoch; - - sets.Add(set); - } - - idOffset = sets.First().OnlineID; - }); - - loadBeatmaps(sets); - - AddStep("Sort by artist", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Artist }, false)); - AddAssert("Items remain in original order", () => carousel.BeatmapSets.Select((set, index) => set.OnlineID == idOffset + index).All(b => b)); - - AddStep("Sort by title", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Title }, false)); - AddAssert("Items are in reverse order", () => carousel.BeatmapSets.Select((set, index) => set.OnlineID == idOffset + sets.Count - index - 1).All(b => b)); - - AddStep("Sort by artist", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Artist }, false)); - AddAssert("Items reset to original order", () => carousel.BeatmapSets.Select((set, index) => set.OnlineID == idOffset + index).All(b => b)); - } - /// /// Ensures stability is maintained on different sort modes while a new item is added to the carousel. /// @@ -664,7 +620,6 @@ namespace osu.Game.Tests.Visual.SongSelect public void TestSortingStabilityWithRemovedAndReaddedItem() { List sets = new List(); - int idOffset = 0; AddStep("Populuate beatmap sets", () => { @@ -685,28 +640,24 @@ namespace osu.Game.Tests.Visual.SongSelect sets.Add(set); } - - idOffset = sets.First().OnlineID; }); + Guid[] originalOrder = null!; + loadBeatmaps(sets); AddStep("Sort by artist", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Artist }, false)); - assertOriginalOrderMaintained(); + + AddAssert("Items in descending added order", () => carousel.BeatmapSets.Select(s => s.DateAdded), () => Is.Ordered.Descending); + AddStep("Save order", () => originalOrder = carousel.BeatmapSets.Select(s => s.ID).ToArray()); AddStep("Remove item", () => carousel.RemoveBeatmapSet(sets[1])); AddStep("Re-add item", () => carousel.UpdateBeatmapSet(sets[1])); - assertOriginalOrderMaintained(); + AddAssert("Order didn't change", () => carousel.BeatmapSets.Select(s => s.ID), () => Is.EqualTo(originalOrder)); AddStep("Sort by title", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Title }, false)); - assertOriginalOrderMaintained(); - - void assertOriginalOrderMaintained() - { - AddAssert("Items remain in original order", - () => carousel.BeatmapSets.Select(s => s.OnlineID), () => Is.EqualTo(carousel.BeatmapSets.Select((set, index) => idOffset + index))); - } + AddAssert("Order didn't change", () => carousel.BeatmapSets.Select(s => s.ID), () => Is.EqualTo(originalOrder)); } /// @@ -716,7 +667,6 @@ namespace osu.Game.Tests.Visual.SongSelect public void TestSortingStabilityWithNewItems() { List sets = new List(); - int idOffset = 0; AddStep("Populuate beatmap sets", () => { @@ -737,14 +687,16 @@ namespace osu.Game.Tests.Visual.SongSelect sets.Add(set); } - - idOffset = sets.First().OnlineID; }); + Guid[] originalOrder = null!; + loadBeatmaps(sets); AddStep("Sort by artist", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Artist }, false)); - assertOriginalOrderMaintained(); + + AddAssert("Items in descending added order", () => carousel.BeatmapSets.Select(s => s.DateAdded), () => Is.Ordered.Descending); + AddStep("Save order", () => originalOrder = carousel.BeatmapSets.Select(s => s.ID).ToArray()); AddStep("Add new item", () => { @@ -756,22 +708,18 @@ namespace osu.Game.Tests.Visual.SongSelect beatmap.Metadata.Artist = "same artist"; beatmap.Metadata.Title = "same title"; - // testing the case where DateAdded happens to equal (quite rare). - set.DateAdded = DateTimeOffset.UnixEpoch; + set.DateAdded = DateTimeOffset.FromUnixTimeSeconds(1); carousel.UpdateBeatmapSet(set); + + // add set to expected ordering + originalOrder = originalOrder.Prepend(set.ID).ToArray(); }); - assertOriginalOrderMaintained(); + AddAssert("Order didn't change", () => carousel.BeatmapSets.Select(s => s.ID), () => Is.EqualTo(originalOrder)); AddStep("Sort by title", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Title }, false)); - assertOriginalOrderMaintained(); - - void assertOriginalOrderMaintained() - { - AddAssert("Items remain in original order", - () => carousel.BeatmapSets.Select(s => s.OnlineID), () => Is.EqualTo(carousel.BeatmapSets.Select((set, index) => idOffset + index))); - } + AddAssert("Order didn't change", () => carousel.BeatmapSets.Select(s => s.ID), () => Is.EqualTo(originalOrder)); } [Test] diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs index 7c919d3586..6004c1c04e 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs @@ -121,14 +121,10 @@ namespace osu.Game.Screens.Select.Carousel if (comparison != 0) return comparison; - // If the initial sort could not differentiate, attempt to use DateAdded and OnlineID to order sets in a stable fashion. - // This directionality is a touch arbitrary as while DateAdded puts newer beatmaps first, the OnlineID fallback puts lower IDs first. - // Can potentially be changed in the future if users actually notice / have preference, but keeping it this way matches historical tests. - + // If the initial sort could not differentiate, attempt to use DateAdded to order sets in a stable fashion. + // The directionality of this matches the current SortMode.DateAdded, but we may want to reconsider if that becomes a user decision (ie. asc / desc). comparison = otherSet.BeatmapSet.DateAdded.CompareTo(BeatmapSet.DateAdded); - if (comparison != 0) return comparison; - comparison = BeatmapSet.OnlineID.CompareTo(otherSet.BeatmapSet.OnlineID); if (comparison != 0) return comparison; // If no online ID is available, fallback to our internal GUID for stability. From 24ed84aad04b1e2c6d04375f5553e6061836f97d Mon Sep 17 00:00:00 2001 From: StanR Date: Wed, 18 Jan 2023 16:25:11 +0300 Subject: [PATCH 212/376] 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 213/376] 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 18baf3dd5d618b66e237809a0eb61da51af858b7 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Wed, 18 Jan 2023 17:30:34 +0300 Subject: [PATCH 214/376] Log delete failure --- osu.Game/Overlays/Comments/DrawableComment.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 1df65ab4b1..59ac4b3254 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -22,6 +22,7 @@ using System.Collections.Specialized; using System.Diagnostics; using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Localisation; +using osu.Framework.Logging; using osu.Framework.Platform; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; @@ -419,8 +420,9 @@ namespace osu.Game.Overlays.Comments if (!ShowDeleted.Value) Hide(); }); - request.Failure += _ => Schedule(() => + request.Failure += e => Schedule(() => { + Logger.Error(e, "Failed to delete comment"); actionsLoading.Hide(); actionsContainer.Show(); }); From c9375c056e3444b4e0fe9730b31ee025ddf3aa95 Mon Sep 17 00:00:00 2001 From: Wleter Date: Wed, 18 Jan 2023 15:54:24 +0100 Subject: [PATCH 215/376] 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 0f2ca5d5ed4391c23e7360170e287bbe1ad06c67 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Wed, 18 Jan 2023 18:10:35 +0300 Subject: [PATCH 216/376] Expose method for drawable comment creation --- osu.Game/Overlays/Comments/CommentsContainer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index a334fac215..c4e4700674 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -301,7 +301,7 @@ namespace osu.Game.Overlays.Comments void addNewComment(Comment comment) { - var drawableComment = getDrawableComment(comment); + var drawableComment = GetDrawableComment(comment); if (comment.ParentId == null) { @@ -333,7 +333,7 @@ namespace osu.Game.Overlays.Comments if (CommentDictionary.ContainsKey(comment.Id)) continue; - topLevelComments.Add(getDrawableComment(comment)); + topLevelComments.Add(GetDrawableComment(comment)); } if (topLevelComments.Any()) @@ -351,7 +351,7 @@ namespace osu.Game.Overlays.Comments } } - private DrawableComment getDrawableComment(Comment comment) + public DrawableComment GetDrawableComment(Comment comment) { if (CommentDictionary.TryGetValue(comment.Id, out var existing)) return existing; From 7ba448b13c53dd7b95f9f686f8f0c96bd1f73dcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 18 Jan 2023 17:12:57 +0100 Subject: [PATCH 217/376] Update comment to match implementation --- osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs index 6004c1c04e..c52b81f915 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs @@ -127,7 +127,7 @@ namespace osu.Game.Screens.Select.Carousel if (comparison != 0) return comparison; - // If no online ID is available, fallback to our internal GUID for stability. + // If DateAdded fails to break the tie, fallback to our internal GUID for stability. // This basically means it's a stable random sort. return otherSet.BeatmapSet.ID.CompareTo(BeatmapSet.ID); } 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 218/376] 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 219/376] 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 c74500b4b4c4010dc8223a4abc58a954a50c12ca Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Wed, 18 Jan 2023 20:49:07 +0300 Subject: [PATCH 220/376] Add reply editor --- osu.Game/Overlays/Comments/DrawableComment.cs | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 59ac4b3254..a737f014d7 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -576,5 +576,52 @@ namespace osu.Game.Overlays.Comments return parentComment.HasMessage ? parentComment.Message : parentComment.IsDeleted ? CommentsStrings.Deleted : string.Empty; } } + + private partial class ReplyCommentEditor : CancellableCommentEditor + { + [Resolved] + private CommentsContainer commentsContainer { get; set; } = null!; + + [Resolved] + private IAPIProvider api { get; set; } = null!; + + private readonly Comment parentComment; + + public Action? OnPost; + + protected override LocalisableString FooterText => default; + protected override LocalisableString CommitButtonText => CommonStrings.ButtonsReply; + protected override LocalisableString TextBoxPlaceholder => CommentsStrings.PlaceholderReply; + + public ReplyCommentEditor(Comment parent) + { + parentComment = parent; + OnCancel = () => this.FadeOut(200).Expire(); + } + + protected override void OnCommit(string text) + { + ShowLoadingSpinner = true; + CommentPostRequest req = new CommentPostRequest(commentsContainer.Type.Value, commentsContainer.Id.Value, text, parentComment.Id); + req.Failure += e => Schedule(() => + { + ShowLoadingSpinner = false; + Logger.Error(e, "Posting reply comment failed."); + }); + req.Success += cb => Schedule(processPostedComments, cb); + api.Queue(req); + } + + private void processPostedComments(CommentBundle cb) + { + foreach (var comment in cb.Comments) + comment.ParentComment = parentComment; + + var drawables = cb.Comments.Select(commentsContainer.GetDrawableComment).ToArray(); + OnPost?.Invoke(drawables); + + OnCancel!.Invoke(); + } + } } } From 0d91277ea59abf0613c32a50c0b849a342e71fae Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Wed, 18 Jan 2023 20:49:30 +0300 Subject: [PATCH 221/376] Add ability to change number on replies button --- osu.Game/Overlays/Comments/Buttons/ShowRepliesButton.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Comments/Buttons/ShowRepliesButton.cs b/osu.Game/Overlays/Comments/Buttons/ShowRepliesButton.cs index aa9b2df7e4..555823e996 100644 --- a/osu.Game/Overlays/Comments/Buttons/ShowRepliesButton.cs +++ b/osu.Game/Overlays/Comments/Buttons/ShowRepliesButton.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 Humanizer; using osu.Framework.Bindables; using osu.Framework.Input.Events; @@ -15,7 +13,12 @@ namespace osu.Game.Overlays.Comments.Buttons public ShowRepliesButton(int count) { - Text = "reply".ToQuantity(count); + Count = count; + } + + public int Count + { + set => Text = "reply".ToQuantity(value); } protected override void LoadComplete() From 77bc4fbf704c7ccdb033fdc8a91f60371428e99e Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Wed, 18 Jan 2023 20:50:07 +0300 Subject: [PATCH 222/376] Integrate editor into comment --- osu.Game/Overlays/Comments/DrawableComment.cs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index a737f014d7..0ec793abca 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -75,6 +75,7 @@ namespace osu.Game.Overlays.Comments private OsuSpriteText deletedLabel = null!; private GridContainer content = null!; private VotePill votePill = null!; + private Container replyEditorContainer = null!; [Resolved] private IDialogOverlay? dialogOverlay { get; set; } @@ -233,6 +234,12 @@ namespace osu.Game.Overlays.Comments } } }, + replyEditorContainer = new Container + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Padding = new MarginPadding { Top = 10 }, + }, new Container { AutoSizeAxes = Axes.Both, @@ -255,6 +262,7 @@ namespace osu.Game.Overlays.Comments }, childCommentsVisibilityContainer = new FillFlowContainer { + Name = @"Children comments", RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Direction = FillDirection.Vertical, @@ -345,6 +353,8 @@ namespace osu.Game.Overlays.Comments actionsContainer.AddLink(CommonStrings.ButtonsPermalink, copyUrl); actionsContainer.AddArbitraryDrawable(Empty().With(d => d.Width = 10)); + actionsContainer.AddLink(CommonStrings.ButtonsReply.ToLower(), toggleReply); + actionsContainer.AddArbitraryDrawable(Empty().With(d => d.Width = 10)); if (Comment.UserId.HasValue && Comment.UserId.Value == api.LocalUser.Value.Id) actionsContainer.AddLink(CommonStrings.ButtonsDelete.ToLower(), deleteComment); @@ -435,6 +445,26 @@ namespace osu.Game.Overlays.Comments onScreenDisplay?.Display(new CopyUrlToast()); } + private void toggleReply() + { + if (replyEditorContainer.Count == 0) + { + replyEditorContainer.Add(new ReplyCommentEditor(Comment) + { + OnPost = comments => + { + Comment.RepliesCount += comments.Length; + showRepliesButton.Count = Comment.RepliesCount; + Replies.AddRange(comments); + } + }); + } + else + { + replyEditorContainer.Clear(true); + } + } + protected override void LoadComplete() { ShowDeleted.BindValueChanged(show => From 7f4d8bdcaaa1d18762802dbf549c276dcc3b72f7 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Wed, 18 Jan 2023 21:27:42 +0300 Subject: [PATCH 223/376] Add test --- .../Visual/Online/TestSceneCommentActions.cs | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index d925141510..124d0c239a 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -11,6 +11,8 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Testing; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -21,6 +23,7 @@ using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.Comments; +using osu.Game.Overlays.Comments.Buttons; using osuTK.Input; namespace osu.Game.Tests.Visual.Online @@ -278,6 +281,93 @@ namespace osu.Game.Tests.Visual.Online AddAssert("Request is correct", () => request != null && request.CommentID == 2 && request.Comment == report_text && request.Reason == CommentReportReason.Other); } + [Test] + public void TestReply() + { + addTestComments(); + DrawableComment? targetComment = null; + AddUntilStep("Comment exists", () => + { + var comments = this.ChildrenOfType(); + targetComment = comments.SingleOrDefault(x => x.Comment.Id == 2); + return targetComment != null; + }); + AddStep("Setup request handling", () => + { + requestLock.Reset(); + + dummyAPI.HandleRequest = r => + { + if (!(r is CommentPostRequest req)) + return false; + + if (req.ParentCommentId != 2) + throw new ArgumentException("Wrong parent ID in request!"); + + if (req.CommentableId != 123 || req.Commentable != CommentableType.Beatmapset) + throw new ArgumentException("Wrong commentable data in request!"); + + Task.Run(() => + { + requestLock.Wait(10000); + req.TriggerSuccess(new CommentBundle + { + Comments = new List + { + new Comment + { + Id = 98, + Message = req.Message, + LegacyName = "FirstUser", + CreatedAt = DateTimeOffset.Now, + VotesCount = 98, + ParentId = req.ParentCommentId, + } + } + }); + }); + + return true; + }; + }); + AddStep("Click reply button", () => + { + var btn = targetComment.ChildrenOfType().Skip(1).First(); + var texts = btn.ChildrenOfType(); + InputManager.MoveMouseTo(texts.Skip(1).First()); + InputManager.Click(MouseButton.Left); + }); + AddAssert("There is 0 replies", () => + { + var replLabel = targetComment.ChildrenOfType().First().ChildrenOfType().First(); + return replLabel.Text.ToString().Contains('0') && targetComment!.Comment.RepliesCount == 0; + }); + AddStep("Focus field", () => + { + InputManager.MoveMouseTo(targetComment.ChildrenOfType().First()); + InputManager.Click(MouseButton.Left); + }); + AddStep("Enter text", () => + { + targetComment.ChildrenOfType().First().Current.Value = "random reply"; + }); + AddStep("Submit", () => + { + InputManager.Key(Key.Enter); + }); + AddStep("Complete request", () => requestLock.Set()); + AddUntilStep("There is 1 reply", () => + { + var replLabel = targetComment.ChildrenOfType().First().ChildrenOfType().First(); + return replLabel.Text.ToString().Contains('1') && targetComment!.Comment.RepliesCount == 1; + }); + AddUntilStep("Submitted comment shown", () => + { + var r = targetComment.ChildrenOfType().Skip(1).FirstOrDefault(); + return r != null && r.Comment.Message == "random reply"; + }); + } + private void addTestComments() { AddStep("set up response", () => From ab78dd0436edd06dba957b54634b30c6ad57807c Mon Sep 17 00:00:00 2001 From: Wleter Date: Wed, 18 Jan 2023 21:34:23 +0100 Subject: [PATCH 224/376] 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 06212bca51eed12d8cf887f3e14a6031344043c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 18 Jan 2023 21:41:00 +0100 Subject: [PATCH 225/376] Restructure test scene to demonstrate failure --- .../Gameplay/TestSceneJudgementCounter.cs | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs index d104e25df0..19c93fab62 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs @@ -25,35 +25,33 @@ namespace osu.Game.Tests.Visual.Gameplay private JudgementTally judgementTally = null!; private TestJudgementCounterDisplay counterDisplay = null!; + private DependencyProvidingContainer content = null!; + + protected override Container Content => content; + private readonly Bindable lastJudgementResult = new Bindable(); private int iteration; [SetUpSteps] - public void SetupSteps() => AddStep("Create components", () => + public void SetUpSteps() => AddStep("Create components", () => { var ruleset = CreateRuleset(); Debug.Assert(ruleset != null); scoreProcessor = new ScoreProcessor(ruleset); - Child = new DependencyProvidingContainer + base.Content.Child = new DependencyProvidingContainer { RelativeSizeAxes = Axes.Both, CachedDependencies = new (Type, object)[] { (typeof(ScoreProcessor), scoreProcessor), (typeof(Ruleset), ruleset) }, Children = new Drawable[] { judgementTally = new JudgementTally(), - new DependencyProvidingContainer + content = new DependencyProvidingContainer { RelativeSizeAxes = Axes.Both, CachedDependencies = new (Type, object)[] { (typeof(JudgementTally), judgementTally) }, - Child = counterDisplay = new TestJudgementCounterDisplay - { - Margin = new MarginPadding { Top = 100 }, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre - } } }, }; @@ -78,6 +76,8 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestAddJudgementsToCounters() { + AddStep("create counter", () => Child = counterDisplay = new TestJudgementCounterDisplay()); + AddRepeatStep("Add judgement", () => applyOneJudgement(HitResult.Great), 2); AddRepeatStep("Add judgement", () => applyOneJudgement(HitResult.Miss), 2); AddRepeatStep("Add judgement", () => applyOneJudgement(HitResult.Meh), 2); @@ -86,6 +86,8 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestAddWhilstHidden() { + AddStep("create counter", () => Child = counterDisplay = new TestJudgementCounterDisplay()); + AddRepeatStep("Add judgement", () => applyOneJudgement(HitResult.LargeTickHit), 2); AddAssert("Check value added whilst hidden", () => hiddenCount() == 2); AddStep("Show all judgements", () => counterDisplay.Mode.Value = JudgementCounterDisplay.DisplayMode.All); @@ -94,6 +96,8 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestChangeFlowDirection() { + AddStep("create counter", () => Child = counterDisplay = new TestJudgementCounterDisplay()); + AddStep("Set direction vertical", () => counterDisplay.FlowDirection.Value = Direction.Vertical); AddStep("Set direction horizontal", () => counterDisplay.FlowDirection.Value = Direction.Horizontal); } @@ -101,6 +105,8 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestToggleJudgementNames() { + AddStep("create counter", () => Child = counterDisplay = new TestJudgementCounterDisplay()); + AddStep("Hide judgement names", () => counterDisplay.ShowJudgementNames.Value = false); AddWaitStep("wait some", 2); AddAssert("Assert hidden", () => counterDisplay.CounterFlow.Children.First().ResultName.Alpha == 0); @@ -112,6 +118,8 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestHideMaxValue() { + AddStep("create counter", () => Child = counterDisplay = new TestJudgementCounterDisplay()); + AddStep("Hide max judgement", () => counterDisplay.ShowMaxJudgement.Value = false); AddWaitStep("wait some", 2); AddAssert("Check max hidden", () => counterDisplay.CounterFlow.ChildrenOfType().First().Alpha == 0); @@ -121,6 +129,8 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestCycleDisplayModes() { + AddStep("create counter", () => Child = counterDisplay = new TestJudgementCounterDisplay()); + AddStep("Show basic judgements", () => counterDisplay.Mode.Value = JudgementCounterDisplay.DisplayMode.Simple); AddWaitStep("wait some", 2); AddAssert("Check only basic", () => counterDisplay.CounterFlow.ChildrenOfType().Last().Alpha == 0); @@ -139,6 +149,13 @@ namespace osu.Game.Tests.Visual.Gameplay private partial class TestJudgementCounterDisplay : JudgementCounterDisplay { public new FillFlowContainer CounterFlow => base.CounterFlow; + + public TestJudgementCounterDisplay() + { + Margin = new MarginPadding { Top = 100 }; + Anchor = Anchor.TopCentre; + Origin = Anchor.TopCentre; + } } } } From 7299d227d1d30d7b46edce5af93084fadf85b64f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 18 Jan 2023 21:42:22 +0100 Subject: [PATCH 226/376] Add failing test case --- .../Visual/Gameplay/TestSceneJudgementCounter.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs index 19c93fab62..46900a2af1 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs @@ -126,6 +126,16 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("Show max judgement", () => counterDisplay.ShowMaxJudgement.Value = true); } + [Test] + public void TestMaxValueStartsHidden() + { + AddStep("create counter", () => Child = counterDisplay = new TestJudgementCounterDisplay + { + ShowMaxJudgement = { Value = false } + }); + AddAssert("Check max hidden", () => counterDisplay.CounterFlow.ChildrenOfType().First().Alpha == 0); + } + [Test] public void TestCycleDisplayModes() { From 40e99069fcbd31174aefbffb03209a247cce5139 Mon Sep 17 00:00:00 2001 From: Wleter Date: Wed, 18 Jan 2023 21:43:09 +0100 Subject: [PATCH 227/376] 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 769f8c61907fe584d09000385ae6d119fc19fff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 18 Jan 2023 21:46:28 +0100 Subject: [PATCH 228/376] Fix `ShowMaxJudgement` callback conflicting with `JudgementCounter.Pop{In,Out}` Both `JudgementCounterDisplay` (via the `ShowMaxJudgement` callback) and the `JudgementCounter.Pop{In,Out}` methods were operating on the alpha of the `JudgementCounter`. This meant that if the counter display was created with max judgement initially hidden, it would be hidden by the `ShowMaxJudgement` callback first, but then _unhidden_ by `PopIn()`. --- .../Play/HUD/JudgementCounter/JudgementCounterDisplay.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs index 4ec90edeb0..e30f8f9be3 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs @@ -68,10 +68,12 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter Mode.BindValueChanged(_ => updateMode(), true); - ShowMaxJudgement.BindValueChanged(value => + ShowMaxJudgement.BindValueChanged(showMax => { var firstChild = CounterFlow.Children.FirstOrDefault(); - firstChild.FadeTo(value.NewValue ? 1 : 0, TRANSFORM_DURATION, Easing.OutQuint); + + if (firstChild != null) + firstChild.State.Value = showMax.NewValue ? Visibility.Visible : Visibility.Hidden; }, true); } From f8d8a627b8d5c75d6fdb2417166be0c537afc731 Mon Sep 17 00:00:00 2001 From: Wleter Date: Wed, 18 Jan 2023 22:00:39 +0100 Subject: [PATCH 229/376] 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 e09b768a99ca1dd988f35df08444c8f4f2f279f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 18 Jan 2023 22:37:26 +0100 Subject: [PATCH 230/376] Add test steps demonstrating failure --- .../Visual/UserInterface/TestSceneSegmentedGraph.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneSegmentedGraph.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneSegmentedGraph.cs index 80941569af..1144b9053d 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneSegmentedGraph.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneSegmentedGraph.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu; @@ -52,7 +53,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("beatmap density with granularity of 200", () => beatmapDensity()); AddStep("beatmap density with granularity of 300", () => beatmapDensity(300)); AddStep("reversed values from 1-10", () => graph.Values = Enumerable.Range(1, 10).Reverse().ToArray()); - AddStep("change colour", () => + AddStep("change tier colours", () => { graph.TierColours = new[] { @@ -62,7 +63,7 @@ namespace osu.Game.Tests.Visual.UserInterface Colour4.Blue }; }); - AddStep("reset colour", () => + AddStep("reset tier colours", () => { graph.TierColours = new[] { @@ -74,6 +75,12 @@ namespace osu.Game.Tests.Visual.UserInterface Colour4.Green }; }); + + AddStep("set graph colour to blue", () => graph.Colour = Colour4.Blue); + AddStep("set graph colour to transparent", () => graph.Colour = Colour4.Transparent); + AddStep("set graph colour to vertical gradient", () => graph.Colour = ColourInfo.GradientVertical(Colour4.White, Colour4.Black)); + AddStep("set graph colour to horizontal gradient", () => graph.Colour = ColourInfo.GradientHorizontal(Colour4.White, Colour4.Black)); + AddStep("reset graph colour", () => graph.Colour = Colour4.White); } private void sinFunction(int size = 100) From 903c37bf3206421b862ff1b386d6db33223e4eb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 18 Jan 2023 22:51:05 +0100 Subject: [PATCH 231/376] Apply draw colour to segmented graph segments --- .../Graphics/UserInterface/SegmentedGraph.cs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/SegmentedGraph.cs b/osu.Game/Graphics/UserInterface/SegmentedGraph.cs index 8ccba710b8..e0be7c1d0f 100644 --- a/osu.Game/Graphics/UserInterface/SegmentedGraph.cs +++ b/osu.Game/Graphics/UserInterface/SegmentedGraph.cs @@ -7,10 +7,12 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Shaders; using osu.Framework.Graphics.Textures; +using osu.Framework.Utils; using osuTK; namespace osu.Game.Graphics.UserInterface @@ -154,7 +156,19 @@ namespace osu.Game.Graphics.UserInterface segments.Sort(); } - private Colour4 getTierColour(int tier) => tier >= 0 ? tierColours[tier] : new Colour4(0, 0, 0, 0); + private ColourInfo getSegmentColour(SegmentInfo segment) + { + var tierColour = segment.Tier >= 0 ? tierColours[segment.Tier] : new Colour4(0, 0, 0, 0); + var ourColour = DrawColourInfo.Colour; + + return new ColourInfo + { + TopLeft = tierColour * Interpolation.ValueAt(segment.Start, ourColour.TopLeft, ourColour.TopRight, 0, 1), + TopRight = tierColour * Interpolation.ValueAt(segment.End, ourColour.TopLeft, ourColour.TopRight, 0, 1), + BottomLeft = tierColour * Interpolation.ValueAt(segment.Start, ourColour.BottomLeft, ourColour.BottomRight, 0, 1), + BottomRight = tierColour * Interpolation.ValueAt(segment.End, ourColour.BottomLeft, ourColour.BottomRight, 0, 1) + }; + } protected override DrawNode CreateDrawNode() => new SegmentedGraphDrawNode(this); @@ -240,7 +254,7 @@ namespace osu.Game.Graphics.UserInterface Vector2Extensions.Transform(topRight, DrawInfo.Matrix), Vector2Extensions.Transform(bottomLeft, DrawInfo.Matrix), Vector2Extensions.Transform(bottomRight, DrawInfo.Matrix)), - Source.getTierColour(segment.Tier)); + Source.getSegmentColour(segment)); } shader.Unbind(); From b8b7442eb826f74d30383c3c8d81d50f097a48f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 18 Jan 2023 23:35:02 +0100 Subject: [PATCH 232/376] Make `SongProgressInfo.ShowProgress` init-only (and remove duplicate init) --- osu.Game/Screens/Play/HUD/ArgonSongProgress.cs | 1 - osu.Game/Screens/Play/HUD/SongProgressInfo.cs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs b/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs index 3a2cd6fe2a..bfee6d295e 100644 --- a/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs +++ b/osu.Game/Screens/Play/HUD/ArgonSongProgress.cs @@ -71,7 +71,6 @@ namespace osu.Game.Screens.Play.HUD [BackgroundDependencyLoader] private void load() { - info.ShowProgress = false; info.TextColour = Colour4.White; info.Font = OsuFont.Torus.With(size: 18, weight: FontWeight.Bold); } diff --git a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs index 8a5c24a1f1..7f9f353ded 100644 --- a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs +++ b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs @@ -53,7 +53,7 @@ namespace osu.Game.Screens.Play.HUD set => startTime = value; } - public bool ShowProgress = true; + public bool ShowProgress { get; init; } = true; public double EndTime { From a0fe71c706a97f1e294dfb5426538d048554b1fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 19 Jan 2023 00:08:32 +0100 Subject: [PATCH 233/376] Use alternative segment colour computation method --- .../Graphics/UserInterface/SegmentedGraph.cs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/SegmentedGraph.cs b/osu.Game/Graphics/UserInterface/SegmentedGraph.cs index e0be7c1d0f..7a004a7f83 100644 --- a/osu.Game/Graphics/UserInterface/SegmentedGraph.cs +++ b/osu.Game/Graphics/UserInterface/SegmentedGraph.cs @@ -12,7 +12,6 @@ using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Shaders; using osu.Framework.Graphics.Textures; -using osu.Framework.Utils; using osuTK; namespace osu.Game.Graphics.UserInterface @@ -158,16 +157,18 @@ namespace osu.Game.Graphics.UserInterface private ColourInfo getSegmentColour(SegmentInfo segment) { - var tierColour = segment.Tier >= 0 ? tierColours[segment.Tier] : new Colour4(0, 0, 0, 0); - var ourColour = DrawColourInfo.Colour; - - return new ColourInfo + var segmentColour = new ColourInfo { - TopLeft = tierColour * Interpolation.ValueAt(segment.Start, ourColour.TopLeft, ourColour.TopRight, 0, 1), - TopRight = tierColour * Interpolation.ValueAt(segment.End, ourColour.TopLeft, ourColour.TopRight, 0, 1), - BottomLeft = tierColour * Interpolation.ValueAt(segment.Start, ourColour.BottomLeft, ourColour.BottomRight, 0, 1), - BottomRight = tierColour * Interpolation.ValueAt(segment.End, ourColour.BottomLeft, ourColour.BottomRight, 0, 1) + 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); From 07af18b8a765f7b17da1241d260d6e8d579682ee Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Jan 2023 16:01:37 +0900 Subject: [PATCH 234/376] Remove `ReplyCommentEditor` into its own class --- osu.Game/Overlays/Comments/DrawableComment.cs | 47 -------------- .../Overlays/Comments/ReplyCommentEditor.cs | 63 +++++++++++++++++++ 2 files changed, 63 insertions(+), 47 deletions(-) create mode 100644 osu.Game/Overlays/Comments/ReplyCommentEditor.cs diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 0ec793abca..7bb8b06ee4 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -606,52 +606,5 @@ namespace osu.Game.Overlays.Comments return parentComment.HasMessage ? parentComment.Message : parentComment.IsDeleted ? CommentsStrings.Deleted : string.Empty; } } - - private partial class ReplyCommentEditor : CancellableCommentEditor - { - [Resolved] - private CommentsContainer commentsContainer { get; set; } = null!; - - [Resolved] - private IAPIProvider api { get; set; } = null!; - - private readonly Comment parentComment; - - public Action? OnPost; - - protected override LocalisableString FooterText => default; - protected override LocalisableString CommitButtonText => CommonStrings.ButtonsReply; - protected override LocalisableString TextBoxPlaceholder => CommentsStrings.PlaceholderReply; - - public ReplyCommentEditor(Comment parent) - { - parentComment = parent; - OnCancel = () => this.FadeOut(200).Expire(); - } - - protected override void OnCommit(string text) - { - ShowLoadingSpinner = true; - CommentPostRequest req = new CommentPostRequest(commentsContainer.Type.Value, commentsContainer.Id.Value, text, parentComment.Id); - req.Failure += e => Schedule(() => - { - ShowLoadingSpinner = false; - Logger.Error(e, "Posting reply comment failed."); - }); - req.Success += cb => Schedule(processPostedComments, cb); - api.Queue(req); - } - - private void processPostedComments(CommentBundle cb) - { - foreach (var comment in cb.Comments) - comment.ParentComment = parentComment; - - var drawables = cb.Comments.Select(commentsContainer.GetDrawableComment).ToArray(); - OnPost?.Invoke(drawables); - - OnCancel!.Invoke(); - } - } } } diff --git a/osu.Game/Overlays/Comments/ReplyCommentEditor.cs b/osu.Game/Overlays/Comments/ReplyCommentEditor.cs new file mode 100644 index 0000000000..450309a1a2 --- /dev/null +++ b/osu.Game/Overlays/Comments/ReplyCommentEditor.cs @@ -0,0 +1,63 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Localisation; +using osu.Framework.Logging; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Resources.Localisation.Web; + +namespace osu.Game.Overlays.Comments +{ + public partial class ReplyCommentEditor : CancellableCommentEditor + { + [Resolved] + private CommentsContainer commentsContainer { get; set; } = null!; + + [Resolved] + private IAPIProvider api { get; set; } = null!; + + private readonly Comment parentComment; + + public Action? OnPost; + + protected override LocalisableString FooterText => default; + protected override LocalisableString CommitButtonText => CommonStrings.ButtonsReply; + protected override LocalisableString TextBoxPlaceholder => CommentsStrings.PlaceholderReply; + + public ReplyCommentEditor(Comment parent) + { + parentComment = parent; + OnCancel = () => this.FadeOut(200).Expire(); + } + + protected override void OnCommit(string text) + { + ShowLoadingSpinner = true; + CommentPostRequest req = new CommentPostRequest(commentsContainer.Type.Value, commentsContainer.Id.Value, text, parentComment.Id); + req.Failure += e => Schedule(() => + { + ShowLoadingSpinner = false; + Logger.Error(e, "Posting reply comment failed."); + }); + req.Success += cb => Schedule(processPostedComments, cb); + api.Queue(req); + } + + private void processPostedComments(CommentBundle cb) + { + foreach (var comment in cb.Comments) + comment.ParentComment = parentComment; + + var drawables = cb.Comments.Select(commentsContainer.GetDrawableComment).ToArray(); + OnPost?.Invoke(drawables); + + OnCancel!.Invoke(); + } + } +} From 81e6c3792c023748896367e0c84deb1f9b6010a9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Jan 2023 16:03:46 +0900 Subject: [PATCH 235/376] Remove unused method --- osu.Game/Overlays/Comments/DrawableComment.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 7bb8b06ee4..4cc189f3a2 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -477,8 +477,6 @@ namespace osu.Game.Overlays.Comments base.LoadComplete(); } - public bool ContainsReply(long replyId) => loadedReplies.ContainsKey(replyId); - private void onRepliesAdded(IEnumerable replies) { var page = createRepliesPage(replies); From 4916a742d5c4e411719fc758d6dca93b07ca2a2c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Jan 2023 16:08:27 +0900 Subject: [PATCH 236/376] Immediately focus the textbox when clicking to reply to a comment --- osu.Game/Overlays/Comments/CommentEditor.cs | 8 ++++---- osu.Game/Overlays/Comments/ReplyCommentEditor.cs | 7 +++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentEditor.cs b/osu.Game/Overlays/Comments/CommentEditor.cs index 769263b3fc..ff417a2e15 100644 --- a/osu.Game/Overlays/Comments/CommentEditor.cs +++ b/osu.Game/Overlays/Comments/CommentEditor.cs @@ -35,6 +35,8 @@ namespace osu.Game.Overlays.Comments private RoundedButton commitButton = null!; private LoadingSpinner loadingSpinner = null!; + protected TextBox TextBox { get; private set; } = null!; + protected bool ShowLoadingSpinner { set @@ -51,8 +53,6 @@ namespace osu.Game.Overlays.Comments [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) { - EditorTextBox textBox; - RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; Masking = true; @@ -74,7 +74,7 @@ namespace osu.Game.Overlays.Comments Direction = FillDirection.Vertical, Children = new Drawable[] { - textBox = new EditorTextBox + TextBox = new EditorTextBox { Height = 40, RelativeSizeAxes = Axes.X, @@ -133,7 +133,7 @@ namespace osu.Game.Overlays.Comments } }); - textBox.OnCommit += (_, _) => commitButton.TriggerClick(); + TextBox.OnCommit += (_, _) => commitButton.TriggerClick(); } protected override void LoadComplete() diff --git a/osu.Game/Overlays/Comments/ReplyCommentEditor.cs b/osu.Game/Overlays/Comments/ReplyCommentEditor.cs index 450309a1a2..e738e6e7ec 100644 --- a/osu.Game/Overlays/Comments/ReplyCommentEditor.cs +++ b/osu.Game/Overlays/Comments/ReplyCommentEditor.cs @@ -36,6 +36,13 @@ namespace osu.Game.Overlays.Comments OnCancel = () => this.FadeOut(200).Expire(); } + protected override void LoadComplete() + { + base.LoadComplete(); + + GetContainingInputManager().ChangeFocus(TextBox); + } + protected override void OnCommit(string text) { ShowLoadingSpinner = true; From b22363ed8cb4709d31c5532649786ff4cb1118fa Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Thu, 19 Jan 2023 10:31:02 +0100 Subject: [PATCH 237/376] Fix JudgementCounterDisplay.cs max judgement always showing upon changing display mode --- .../Gameplay/TestSceneJudgementCounter.cs | 11 +++++++++ .../JudgementCounterDisplay.cs | 23 +++++++++++++------ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs index 46900a2af1..5a802e0d36 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneJudgementCounter.cs @@ -136,6 +136,17 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("Check max hidden", () => counterDisplay.CounterFlow.ChildrenOfType().First().Alpha == 0); } + [Test] + public void TestMaxValueHiddenOnModeChange() + { + AddStep("create counter", () => Child = counterDisplay = new TestJudgementCounterDisplay()); + + AddStep("Set max judgement to hide itself", () => counterDisplay.ShowMaxJudgement.Value = false); + AddStep("Show all judgements", () => counterDisplay.Mode.Value = JudgementCounterDisplay.DisplayMode.All); + AddWaitStep("wait some", 2); + AddAssert("Assert max judgement hidden", () => counterDisplay.CounterFlow.ChildrenOfType().First().Alpha == 0); + } + [Test] public void TestCycleDisplayModes() { diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs index e30f8f9be3..27dd98289a 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs @@ -66,15 +66,16 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter counter.Direction.Value = convertedDirection; }, true); - Mode.BindValueChanged(_ => updateMode(), true); + Mode.BindValueChanged(_ => + { + updateMode(); + + //Refreshing the counter causes the first child to become visible, so we want to make sure it isn't if it shouldn't be + updateFirstChildVisibility(); + }, true); ShowMaxJudgement.BindValueChanged(showMax => - { - var firstChild = CounterFlow.Children.FirstOrDefault(); - - if (firstChild != null) - firstChild.State.Value = showMax.NewValue ? Visibility.Visible : Visibility.Hidden; - }, true); + updateFirstChildVisibility(), true); } private void updateMode() @@ -109,6 +110,14 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter } } + private void updateFirstChildVisibility() + { + var firstChild = CounterFlow.Children.FirstOrDefault(); + + if (firstChild != null) + firstChild.State.Value = ShowMaxJudgement.Value ? Visibility.Visible : Visibility.Hidden; + } + private FillDirection getFillDirection(Direction flow) { switch (flow) From 2ce32e3209f8ebab80871fee8b91c3ff772d5dd8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Jan 2023 19:27:05 +0900 Subject: [PATCH 238/376] Refactor update logic to be easier to follow --- .../JudgementCounterDisplay.cs | 34 ++++++------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs index 27dd98289a..82f24c736e 100644 --- a/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs +++ b/osu.Game/Screens/Play/HUD/JudgementCounter/JudgementCounterDisplay.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -66,30 +65,27 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter counter.Direction.Value = convertedDirection; }, true); - Mode.BindValueChanged(_ => - { - updateMode(); - - //Refreshing the counter causes the first child to become visible, so we want to make sure it isn't if it shouldn't be - updateFirstChildVisibility(); - }, true); - - ShowMaxJudgement.BindValueChanged(showMax => - updateFirstChildVisibility(), true); + Mode.BindValueChanged(_ => updateDisplay()); + ShowMaxJudgement.BindValueChanged(_ => updateDisplay(), true); } - private void updateMode() + private void updateDisplay() { - foreach (var counter in CounterFlow.Children) + for (int i = 0; i < CounterFlow.Children.Count; i++) { - if (shouldShow(counter)) + JudgementCounter counter = CounterFlow.Children[i]; + + if (shouldShow(i, counter)) counter.Show(); else counter.Hide(); } - bool shouldShow(JudgementCounter counter) + bool shouldShow(int index, JudgementCounter counter) { + if (index == 0 && !ShowMaxJudgement.Value) + return false; + if (counter.Result.Type.IsBasic()) return true; @@ -110,14 +106,6 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter } } - private void updateFirstChildVisibility() - { - var firstChild = CounterFlow.Children.FirstOrDefault(); - - if (firstChild != null) - firstChild.State.Value = ShowMaxJudgement.Value ? Visibility.Visible : Visibility.Hidden; - } - private FillDirection getFillDirection(Direction flow) { switch (flow) From f0464b0340172cf6139d04ec5cc1ca68581ee556 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 19 Jan 2023 22:38:54 +0300 Subject: [PATCH 239/376] Actually fix intermittent failure in beatmap options state test --- osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index a61171abad..feab86d3ee 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -1064,7 +1064,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddAssert("options enabled", () => songSelect.ChildrenOfType().Single().Enabled.Value); AddStep("delete all beatmaps", () => manager.Delete()); - AddWaitStep("wait for debounce", 1); + AddUntilStep("wait for no beatmap", () => Beatmap.IsDefault); AddAssert("options disabled", () => !songSelect.ChildrenOfType().Single().Enabled.Value); } From 8174ef06c3caaabdbd6a5c89410d18caf227d5ff Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 20 Jan 2023 01:18:41 +0300 Subject: [PATCH 240/376] Fix intermittent failure in playlists match loading test --- .../Visual/Playlists/TestScenePlaylistsRoomCreation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs index bdae91de59..6c732f4295 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs @@ -79,7 +79,7 @@ namespace osu.Game.Tests.Visual.Playlists AddUntilStep("Leaderboard shows two aggregate scores", () => match.ChildrenOfType().Count(s => s.ScoreText.Text != "0") == 2); - AddStep("start match", () => match.ChildrenOfType().First().TriggerClick()); + ClickButtonWhenEnabled(); AddUntilStep("player loader loaded", () => Stack.CurrentScreen is PlayerLoader); } From 7e466e1eba35c196a5039a40c881f829fe9f4959 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 20 Jan 2023 21:00:01 +0900 Subject: [PATCH 241/376] Fix SPM calculation division by zero --- .../Skinning/Default/SpinnerSpmCalculator.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerSpmCalculator.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerSpmCalculator.cs index 0bd5fd4cac..44962c8548 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerSpmCalculator.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerSpmCalculator.cs @@ -35,14 +35,14 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default public void SetRotation(float currentRotation) { - // Never calculate SPM by same time of record to avoid 0 / 0 = NaN or X / 0 = Infinity result. - if (Precision.AlmostEquals(0, Time.Elapsed)) - return; - // If we've gone back in time, it's fine to work with a fresh set of records for now if (records.Count > 0 && Time.Current < records.Last().Time) records.Clear(); + // Never calculate SPM by same time of record to avoid 0 / 0 = NaN or X / 0 = Infinity result. + if (records.Count > 0 && Precision.AlmostEquals(Time.Current, records.Last().Time)) + return; + if (records.Count > 0) { var record = records.Peek(); From 19450bfe12e5742a161cff59f9f3ebbf8fe1ac59 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Jan 2023 23:23:25 +0900 Subject: [PATCH 242/376] 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 c6cf7812d1..71944065bf 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -10,7 +10,7 @@ true - +