From 962c95dc0158bfddf43ad8128dc4e1db2a131cb6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 4 Jan 2021 19:06:00 +0900 Subject: [PATCH 1/8] Fix ModSelection making unsafe advances of ModSection --- osu.Game/Overlays/Mods/ModSection.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModSection.cs b/osu.Game/Overlays/Mods/ModSection.cs index 0107f94dcf..d00a365dde 100644 --- a/osu.Game/Overlays/Mods/ModSection.cs +++ b/osu.Game/Overlays/Mods/ModSection.cs @@ -130,7 +130,7 @@ namespace osu.Game.Overlays.Mods /// Select one or more mods in this section and deselects all other ones. /// /// The types of s which should be selected. - public void SelectTypes(IEnumerable modTypes) + public void SelectTypes(IEnumerable modTypes) => Schedule(() => { foreach (var button in buttons) { @@ -141,7 +141,7 @@ namespace osu.Game.Overlays.Mods else button.Deselect(); } - } + }); protected ModSection() { From 57a8cd74615765e54d60a425f904a4034045b1a0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Jan 2021 16:17:55 +0900 Subject: [PATCH 2/8] Schedule deselection operations for safety --- osu.Game/Overlays/Mods/ModSection.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModSection.cs b/osu.Game/Overlays/Mods/ModSection.cs index d00a365dde..47b101c2b0 100644 --- a/osu.Game/Overlays/Mods/ModSection.cs +++ b/osu.Game/Overlays/Mods/ModSection.cs @@ -104,7 +104,7 @@ namespace osu.Game.Overlays.Mods /// /// The types of s which should be deselected. /// Set to true to bypass animations and update selections immediately. - public void DeselectTypes(IEnumerable modTypes, bool immediate = false) + public void DeselectTypes(IEnumerable modTypes, bool immediate = false) => Schedule(() => { int delay = 0; @@ -124,7 +124,7 @@ namespace osu.Game.Overlays.Mods } } } - } + }); /// /// Select one or more mods in this section and deselects all other ones. From 9bac791a576a0b16860f3addb3ef3a451d166d1c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Jan 2021 16:17:42 +0900 Subject: [PATCH 3/8] Fix deselection of autoplay mod failing --- osu.Game/Screens/Select/PlaySongSelect.cs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 50a61ed4c2..e61d5cce85 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -9,6 +9,7 @@ using osu.Framework.Screens; using osu.Game.Graphics; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; +using osu.Game.Rulesets.Mods; using osu.Game.Scoring; using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; @@ -42,6 +43,8 @@ namespace osu.Game.Screens.Select protected override BeatmapDetailArea CreateBeatmapDetailArea() => new PlayBeatmapDetailArea(); + private ModAutoplay getAutoplayMod() => Ruleset.Value.CreateInstance().GetAutoplayMod(); + public override void OnResuming(IScreen last) { base.OnResuming(last); @@ -50,10 +53,10 @@ namespace osu.Game.Screens.Select if (removeAutoModOnResume) { - var autoType = Ruleset.Value.CreateInstance().GetAutoplayMod()?.GetType(); + var autoType = getAutoplayMod()?.GetType(); if (autoType != null) - ModSelect.DeselectTypes(new[] { autoType }, true); + Mods.Value = Mods.Value.Where(m => m.GetType() != autoType).ToArray(); removeAutoModOnResume = false; } @@ -81,12 +84,9 @@ namespace osu.Game.Screens.Select // Ctrl+Enter should start map with autoplay enabled. if (GetContainingInputManager().CurrentState?.Keyboard.ControlPressed == true) { - var auto = Ruleset.Value.CreateInstance().GetAutoplayMod(); - var autoType = auto?.GetType(); + var autoplayMod = getAutoplayMod(); - var mods = Mods.Value; - - if (autoType == null) + if (autoplayMod == null) { notifications?.Post(new SimpleNotification { @@ -95,9 +95,11 @@ namespace osu.Game.Screens.Select return false; } - if (mods.All(m => m.GetType() != autoType)) + var mods = Mods.Value; + + if (mods.All(m => m.GetType() != autoplayMod.GetType())) { - Mods.Value = mods.Append(auto).ToArray(); + Mods.Value = mods.Append(autoplayMod).ToArray(); removeAutoModOnResume = true; } } From 4d6c13f169cc7c09c4db61bbfdfd780c5b44fef5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Jan 2021 16:18:13 +0900 Subject: [PATCH 4/8] Privatise ModSelectOverlay methods that may be unsafe to be called externally --- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 34f5c70adb..491052fa2c 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -249,7 +249,7 @@ namespace osu.Game.Overlays.Mods { Width = 180, Text = "Deselect All", - Action = DeselectAll, + Action = deselectAll, Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, }, @@ -318,7 +318,7 @@ namespace osu.Game.Overlays.Mods sampleOff = audio.Samples.Get(@"UI/check-off"); } - public void DeselectAll() + private void deselectAll() { foreach (var section in ModSectionsContainer.Children) section.DeselectAll(); @@ -331,7 +331,7 @@ namespace osu.Game.Overlays.Mods /// /// The types of s which should be deselected. /// Set to true to bypass animations and update selections immediately. - public void DeselectTypes(Type[] modTypes, bool immediate = false) + private void deselectTypes(Type[] modTypes, bool immediate = false) { if (modTypes.Length == 0) return; @@ -438,7 +438,7 @@ namespace osu.Game.Overlays.Mods { if (State.Value == Visibility.Visible) sampleOn?.Play(); - DeselectTypes(selectedMod.IncompatibleMods, true); + deselectTypes(selectedMod.IncompatibleMods, true); if (selectedMod.RequiresConfiguration) ModSettingsContainer.Show(); } From 5d8c153c1e21949156a0dbf54b9cf8d71bca4c4d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Jan 2021 16:41:03 +0900 Subject: [PATCH 5/8] Move schedule logic to buttons rather than section It turns out there's some quite convoluted scheduling / order of execution requirements of ModSelectOverlay and ModSection. Applying scheduling causes a runaway condition ending in zero frames after many mod button changes. I wanted to avoid rewriting the whole component, so have just moved the schedule to guard against the part where drawables are actually changed. --- osu.Game/Overlays/Mods/ModButton.cs | 62 +++++++++++++++------------- osu.Game/Overlays/Mods/ModSection.cs | 8 ++-- 2 files changed, 37 insertions(+), 33 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index e574828cd2..51c8bcf9a9 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -64,41 +64,45 @@ namespace osu.Game.Overlays.Mods if (newIndex >= 0 && !Mods[newIndex].HasImplementation) return false; - selectedIndex = newIndex; - Mod modAfter = SelectedMod ?? Mods[0]; - - if (beforeSelected != Selected) + Schedule(() => { - iconsContainer.RotateTo(Selected ? 5f : 0f, 300, Easing.OutElastic); - iconsContainer.ScaleTo(Selected ? 1.1f : 1f, 300, Easing.OutElastic); - } + selectedIndex = newIndex; + Mod modAfter = SelectedMod ?? Mods[0]; - if (modBefore != modAfter) - { - const float rotate_angle = 16; - - foregroundIcon.RotateTo(rotate_angle * direction, mod_switch_duration, mod_switch_easing); - backgroundIcon.RotateTo(-rotate_angle * direction, mod_switch_duration, mod_switch_easing); - - backgroundIcon.Mod = modAfter; - - using (BeginDelayedSequence(mod_switch_duration, true)) + if (beforeSelected != Selected) { - foregroundIcon - .RotateTo(-rotate_angle * direction) - .RotateTo(0f, mod_switch_duration, mod_switch_easing); - - backgroundIcon - .RotateTo(rotate_angle * direction) - .RotateTo(0f, mod_switch_duration, mod_switch_easing); - - Schedule(() => displayMod(modAfter)); + iconsContainer.RotateTo(Selected ? 5f : 0f, 300, Easing.OutElastic); + iconsContainer.ScaleTo(Selected ? 1.1f : 1f, 300, Easing.OutElastic); } - } - foregroundIcon.Selected.Value = Selected; + if (modBefore != modAfter) + { + const float rotate_angle = 16; + + foregroundIcon.RotateTo(rotate_angle * direction, mod_switch_duration, mod_switch_easing); + backgroundIcon.RotateTo(-rotate_angle * direction, mod_switch_duration, mod_switch_easing); + + backgroundIcon.Mod = modAfter; + + using (BeginDelayedSequence(mod_switch_duration, true)) + { + foregroundIcon + .RotateTo(-rotate_angle * direction) + .RotateTo(0f, mod_switch_duration, mod_switch_easing); + + backgroundIcon + .RotateTo(rotate_angle * direction) + .RotateTo(0f, mod_switch_duration, mod_switch_easing); + + Schedule(() => displayMod(modAfter)); + } + } + + foregroundIcon.Selected.Value = Selected; + + SelectionChanged?.Invoke(SelectedMod); + }); - SelectionChanged?.Invoke(SelectedMod); return true; } diff --git a/osu.Game/Overlays/Mods/ModSection.cs b/osu.Game/Overlays/Mods/ModSection.cs index 47b101c2b0..0107f94dcf 100644 --- a/osu.Game/Overlays/Mods/ModSection.cs +++ b/osu.Game/Overlays/Mods/ModSection.cs @@ -104,7 +104,7 @@ namespace osu.Game.Overlays.Mods /// /// The types of s which should be deselected. /// Set to true to bypass animations and update selections immediately. - public void DeselectTypes(IEnumerable modTypes, bool immediate = false) => Schedule(() => + public void DeselectTypes(IEnumerable modTypes, bool immediate = false) { int delay = 0; @@ -124,13 +124,13 @@ namespace osu.Game.Overlays.Mods } } } - }); + } /// /// Select one or more mods in this section and deselects all other ones. /// /// The types of s which should be selected. - public void SelectTypes(IEnumerable modTypes) => Schedule(() => + public void SelectTypes(IEnumerable modTypes) { foreach (var button in buttons) { @@ -141,7 +141,7 @@ namespace osu.Game.Overlays.Mods else button.Deselect(); } - }); + } protected ModSection() { From c208800150494eceb06472e45310eecc8859b29b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Jan 2021 14:17:14 +0900 Subject: [PATCH 6/8] Fix auto selection scenario regressing due to scheduling too much --- osu.Game/Overlays/Mods/ModButton.cs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index 51c8bcf9a9..b58e70cae6 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -52,9 +52,10 @@ namespace osu.Game.Overlays.Mods if (newIndex == selectedIndex) return false; int direction = newIndex < selectedIndex ? -1 : 1; + bool beforeSelected = Selected; - Mod modBefore = SelectedMod ?? Mods[0]; + Mod previousSelection = SelectedMod ?? Mods[0]; if (newIndex >= Mods.Length) newIndex = -1; @@ -64,25 +65,26 @@ namespace osu.Game.Overlays.Mods if (newIndex >= 0 && !Mods[newIndex].HasImplementation) return false; + selectedIndex = newIndex; + + Mod newSelection = SelectedMod ?? Mods[0]; + Schedule(() => { - selectedIndex = newIndex; - Mod modAfter = SelectedMod ?? Mods[0]; - if (beforeSelected != Selected) { iconsContainer.RotateTo(Selected ? 5f : 0f, 300, Easing.OutElastic); iconsContainer.ScaleTo(Selected ? 1.1f : 1f, 300, Easing.OutElastic); } - if (modBefore != modAfter) + if (previousSelection != newSelection) { const float rotate_angle = 16; foregroundIcon.RotateTo(rotate_angle * direction, mod_switch_duration, mod_switch_easing); backgroundIcon.RotateTo(-rotate_angle * direction, mod_switch_duration, mod_switch_easing); - backgroundIcon.Mod = modAfter; + backgroundIcon.Mod = newSelection; using (BeginDelayedSequence(mod_switch_duration, true)) { @@ -94,15 +96,15 @@ namespace osu.Game.Overlays.Mods .RotateTo(rotate_angle * direction) .RotateTo(0f, mod_switch_duration, mod_switch_easing); - Schedule(() => displayMod(modAfter)); + Schedule(() => displayMod(newSelection)); } } foregroundIcon.Selected.Value = Selected; - - SelectionChanged?.Invoke(SelectedMod); }); + SelectionChanged?.Invoke(newSelection); + return true; } From 0cf5be3ef432a718d23bab4fc951f04182375ebb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 8 Jan 2021 17:02:57 +0100 Subject: [PATCH 7/8] Fix selection change event being invoked with wrong mod --- osu.Game/Overlays/Mods/ModButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index b58e70cae6..ab8efdabcc 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -103,7 +103,7 @@ namespace osu.Game.Overlays.Mods foregroundIcon.Selected.Value = Selected; }); - SelectionChanged?.Invoke(newSelection); + SelectionChanged?.Invoke(SelectedMod); return true; } From 8feaf3fb6ad084885f8b69b997caea7faf92bb50 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 9 Jan 2021 01:24:18 +0900 Subject: [PATCH 8/8] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 611f0d05f4..492c88c7e4 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,6 +52,6 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 6c220a5c21..f28a55e016 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -26,7 +26,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 5445adb3fb..93be3645ee 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -88,7 +88,7 @@ - +