From 0a78eb96289c5f38ab8447daeaedbcb55a290a55 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Thu, 29 Aug 2024 21:54:47 +0200 Subject: [PATCH 01/12] Implement auto additions editor-only --- osu.Game/Audio/HitSampleInfo.cs | 13 +++- .../Beatmaps/Formats/LegacyBeatmapEncoder.cs | 2 +- osu.Game/Rulesets/Objects/HitObject.cs | 2 +- .../Objects/Legacy/ConvertHitObjectParser.cs | 33 ++++++---- .../Components/EditorSelectionHandler.cs | 60 ++++++++----------- .../Components/Timeline/SamplePointPiece.cs | 37 ++++++++---- 6 files changed, 87 insertions(+), 60 deletions(-) diff --git a/osu.Game/Audio/HitSampleInfo.cs b/osu.Game/Audio/HitSampleInfo.cs index ce5e2175328a..19273e3714e4 100644 --- a/osu.Game/Audio/HitSampleInfo.cs +++ b/osu.Game/Audio/HitSampleInfo.cs @@ -60,12 +60,18 @@ public class HitSampleInfo : ISampleInfo, IEquatable /// public int Volume { get; } - public HitSampleInfo(string name, string bank = SampleControlPoint.DEFAULT_BANK, string? suffix = null, int volume = 100) + /// + /// Whether this sample should automatically assign the bank of the normal sample whenever it is set in the editor. + /// + public bool EditorAutoBank { get; } + + public HitSampleInfo(string name, string bank = SampleControlPoint.DEFAULT_BANK, string? suffix = null, int volume = 100, bool editorAutoBank = true) { Name = name; Bank = bank; Suffix = suffix; Volume = volume; + EditorAutoBank = editorAutoBank; } /// @@ -92,9 +98,10 @@ public virtual IEnumerable LookupNames /// An optional new sample bank. /// An optional new lookup suffix. /// An optional new volume. + /// An optional new editor auto bank flag. /// The new . - public virtual HitSampleInfo With(Optional newName = default, Optional newBank = default, Optional newSuffix = default, Optional newVolume = default) - => new HitSampleInfo(newName.GetOr(Name), newBank.GetOr(Bank), newSuffix.GetOr(Suffix), newVolume.GetOr(Volume)); + public virtual HitSampleInfo With(Optional newName = default, Optional newBank = default, Optional newSuffix = default, Optional newVolume = default, Optional newEditorAutoBank = default) + => new HitSampleInfo(newName.GetOr(Name), newBank.GetOr(Bank), newSuffix.GetOr(Suffix), newVolume.GetOr(Volume), newEditorAutoBank.GetOr(EditorAutoBank)); public virtual bool Equals(HitSampleInfo? other) => other != null && Name == other.Name && Bank == other.Bank && Suffix == other.Suffix; diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs index b0173b3ae3e1..c14648caf67f 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs @@ -539,7 +539,7 @@ private void addEndTimeData(TextWriter writer, HitObject hitObject) private string getSampleBank(IList samples, bool banksOnly = false) { LegacySampleBank normalBank = toLegacySampleBank(samples.SingleOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL)?.Bank); - LegacySampleBank addBank = toLegacySampleBank(samples.FirstOrDefault(s => !string.IsNullOrEmpty(s.Name) && s.Name != HitSampleInfo.HIT_NORMAL)?.Bank); + LegacySampleBank addBank = toLegacySampleBank(samples.FirstOrDefault(s => !string.IsNullOrEmpty(s.Name) && s.Name != HitSampleInfo.HIT_NORMAL && !s.EditorAutoBank)?.Bank); StringBuilder sb = new StringBuilder(); diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index c547a7a71845..9f980769e276 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -233,7 +233,7 @@ public HitSampleInfo CreateHitSampleInfo(string sampleName = HitSampleInfo.HIT_N // Fall back to using the normal sample bank otherwise. if (Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL) is HitSampleInfo existingNormal) - return existingNormal.With(newName: sampleName); + return existingNormal.With(newName: sampleName, newEditorAutoBank: true); return new HitSampleInfo(sampleName); } diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index c518a3e8b28d..fa3ee41b4747 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -204,8 +204,14 @@ private void readCustomSampleBanks(string str, SampleBankInfo bankInfo, bool ban if (stringBank == @"none") stringBank = null; string stringAddBank = addBank.ToString().ToLowerInvariant(); + if (stringAddBank == @"none") + { + bankInfo.EditorAutoBank = true; stringAddBank = null; + } + else + bankInfo.EditorAutoBank = false; bankInfo.BankForNormal = stringBank; bankInfo.BankForAdditions = string.IsNullOrEmpty(stringAddBank) ? stringBank : stringAddBank; @@ -477,7 +483,7 @@ private List convertSoundType(LegacyHitSoundType type, SampleBank if (string.IsNullOrEmpty(bankInfo.Filename)) { - soundTypes.Add(new LegacyHitSampleInfo(HitSampleInfo.HIT_NORMAL, bankInfo.BankForNormal, bankInfo.Volume, bankInfo.CustomSampleBank, + soundTypes.Add(new LegacyHitSampleInfo(HitSampleInfo.HIT_NORMAL, bankInfo.BankForNormal, bankInfo.Volume, true, bankInfo.CustomSampleBank, // if the sound type doesn't have the Normal flag set, attach it anyway as a layered sample. // None also counts as a normal non-layered sample: https://osu.ppy.sh/help/wiki/osu!_File_Formats/Osu_(file_format)#hitsounds type != LegacyHitSoundType.None && !type.HasFlag(LegacyHitSoundType.Normal))); @@ -489,13 +495,13 @@ private List convertSoundType(LegacyHitSoundType type, SampleBank } if (type.HasFlag(LegacyHitSoundType.Finish)) - soundTypes.Add(new LegacyHitSampleInfo(HitSampleInfo.HIT_FINISH, bankInfo.BankForAdditions, bankInfo.Volume, bankInfo.CustomSampleBank)); + soundTypes.Add(new LegacyHitSampleInfo(HitSampleInfo.HIT_FINISH, bankInfo.BankForAdditions, bankInfo.Volume, bankInfo.EditorAutoBank, bankInfo.CustomSampleBank)); if (type.HasFlag(LegacyHitSoundType.Whistle)) - soundTypes.Add(new LegacyHitSampleInfo(HitSampleInfo.HIT_WHISTLE, bankInfo.BankForAdditions, bankInfo.Volume, bankInfo.CustomSampleBank)); + soundTypes.Add(new LegacyHitSampleInfo(HitSampleInfo.HIT_WHISTLE, bankInfo.BankForAdditions, bankInfo.Volume, bankInfo.EditorAutoBank, bankInfo.CustomSampleBank)); if (type.HasFlag(LegacyHitSoundType.Clap)) - soundTypes.Add(new LegacyHitSampleInfo(HitSampleInfo.HIT_CLAP, bankInfo.BankForAdditions, bankInfo.Volume, bankInfo.CustomSampleBank)); + soundTypes.Add(new LegacyHitSampleInfo(HitSampleInfo.HIT_CLAP, bankInfo.BankForAdditions, bankInfo.Volume, bankInfo.EditorAutoBank, bankInfo.CustomSampleBank)); return soundTypes; } @@ -534,6 +540,11 @@ private class SampleBankInfo /// public int CustomSampleBank; + /// + /// Whether the bank for additions should be inherited from the normal sample in edit. + /// + public bool EditorAutoBank; + public SampleBankInfo Clone() => (SampleBankInfo)MemberwiseClone(); } @@ -558,21 +569,21 @@ public class LegacyHitSampleInfo : HitSampleInfo, IEquatable public bool BankSpecified; - public LegacyHitSampleInfo(string name, string? bank = null, int volume = 0, int customSampleBank = 0, bool isLayered = false) - : base(name, bank ?? SampleControlPoint.DEFAULT_BANK, customSampleBank >= 2 ? customSampleBank.ToString() : null, volume) + public LegacyHitSampleInfo(string name, string? bank = null, int volume = 0, bool editorAutoBank = false, int customSampleBank = 0, bool isLayered = false) + : base(name, bank ?? SampleControlPoint.DEFAULT_BANK, customSampleBank >= 2 ? customSampleBank.ToString() : null, volume, editorAutoBank) { CustomSampleBank = customSampleBank; BankSpecified = !string.IsNullOrEmpty(bank); IsLayered = isLayered; } - public sealed override HitSampleInfo With(Optional newName = default, Optional newBank = default, Optional newSuffix = default, Optional newVolume = default) - => With(newName, newBank, newVolume); + public sealed override HitSampleInfo With(Optional newName = default, Optional newBank = default, Optional newSuffix = default, Optional newVolume = default, Optional newEditorAutoBank = default) + => With(newName, newBank, newVolume, newEditorAutoBank); - public virtual LegacyHitSampleInfo With(Optional newName = default, Optional newBank = default, Optional newVolume = default, + public virtual LegacyHitSampleInfo With(Optional newName = default, Optional newBank = default, Optional newVolume = default, Optional newEditorAutoBank = default, Optional newCustomSampleBank = default, Optional newIsLayered = default) - => new LegacyHitSampleInfo(newName.GetOr(Name), newBank.GetOr(Bank), newVolume.GetOr(Volume), newCustomSampleBank.GetOr(CustomSampleBank), newIsLayered.GetOr(IsLayered)); + => new LegacyHitSampleInfo(newName.GetOr(Name), newBank.GetOr(Bank), newVolume.GetOr(Volume), newEditorAutoBank.GetOr(EditorAutoBank), newCustomSampleBank.GetOr(CustomSampleBank), newIsLayered.GetOr(IsLayered)); public bool Equals(LegacyHitSampleInfo? other) // The additions to equality checks here are *required* to ensure that pooling works correctly. @@ -604,7 +615,7 @@ public FileHitSampleInfo(string filename, int volume) Path.ChangeExtension(Filename, null) }; - public sealed override LegacyHitSampleInfo With(Optional newName = default, Optional newBank = default, Optional newVolume = default, + public sealed override LegacyHitSampleInfo With(Optional newName = default, Optional newBank = default, Optional newVolume = default, Optional newEditorAutoBank = default, Optional newCustomSampleBank = default, Optional newIsLayered = default) => new FileHitSampleInfo(Filename, newVolume.GetOr(Volume)); diff --git a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs index 769240839aa4..8de3f3052f97 100644 --- a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs @@ -152,10 +152,6 @@ private void createStateBindables() } else { - // Auto should never apply when there is a selection made. - if (bankName == HIT_BANK_AUTO) - break; - // Completely empty selections should be allowed in the case that none of the selected objects have any addition samples. // This is also required to stop a bindable feedback loop when a HitObject has zero addition samples (and LINQ `All` below becomes true). if (SelectedItems.SelectMany(enumerateAllSamples).All(h => h.All(o => o.Name == HitSampleInfo.HIT_NORMAL))) @@ -163,8 +159,16 @@ private void createStateBindables() // Never remove a sample bank. // These are basically radio buttons, not toggles. - if (SelectedItems.SelectMany(enumerateAllSamples).All(h => h.Where(o => o.Name != HitSampleInfo.HIT_NORMAL).All(s => s.Bank == bankName))) - bindable.Value = TernaryState.True; + if (bankName == HIT_BANK_AUTO) + { + if (SelectedItems.SelectMany(enumerateAllSamples).All(h => h.Where(o => o.Name != HitSampleInfo.HIT_NORMAL).All(s => s.EditorAutoBank))) + bindable.Value = TernaryState.True; + } + else + { + if (SelectedItems.SelectMany(enumerateAllSamples).All(h => h.Where(o => o.Name != HitSampleInfo.HIT_NORMAL).All(s => s.Bank == bankName && !s.EditorAutoBank))) + bindable.Value = TernaryState.True; + } } break; @@ -182,14 +186,6 @@ private void createStateBindables() } else { - // Auto should just not apply if there's a selection already made. - // Maybe we could make it a disabled button in the future, but right now the editor buttons don't support disabled state. - if (bankName == HIT_BANK_AUTO) - { - bindable.Value = TernaryState.False; - break; - } - // If none of the selected objects have any addition samples, we should not apply the addition bank. if (SelectedItems.SelectMany(enumerateAllSamples).All(h => h.All(o => o.Name == HitSampleInfo.HIT_NORMAL))) { @@ -209,7 +205,7 @@ private void createStateBindables() // start with normal selected. SelectionBankStates[SampleControlPoint.DEFAULT_BANK].Value = TernaryState.True; - SelectionAdditionBankStates[SampleControlPoint.DEFAULT_BANK].Value = TernaryState.True; + SelectionAdditionBankStates[HIT_BANK_AUTO].Value = TernaryState.True; foreach (string sampleName in HitSampleInfo.AllAdditions) { @@ -272,7 +268,7 @@ protected virtual void UpdateTernaryStates() foreach ((string bankName, var bindable) in SelectionAdditionBankStates) { - bindable.Value = GetStateFromSelection(samplesInSelection.SelectMany(s => s).Where(o => o.Name != HitSampleInfo.HIT_NORMAL), h => h.Bank == bankName); + bindable.Value = GetStateFromSelection(samplesInSelection.SelectMany(s => s).Where(o => o.Name != HitSampleInfo.HIT_NORMAL), h => (bankName != HIT_BANK_AUTO && h.Bank == bankName && !h.EditorAutoBank) || (bankName == HIT_BANK_AUTO && h.EditorAutoBank)); } } @@ -336,33 +332,29 @@ bool hasRelevantBank(HitObject hitObject) /// The name of the sample bank. public void SetSampleAdditionBank(string bankName) { - bool hasRelevantBank(HitObject hitObject) - { - bool result = hitObject.Samples.Where(o => o.Name != HitSampleInfo.HIT_NORMAL).All(s => s.Bank == bankName); - - if (hitObject is IHasRepeats hasRepeats) - { - foreach (var node in hasRepeats.NodeSamples) - result &= node.Where(o => o.Name != HitSampleInfo.HIT_NORMAL).All(s => s.Bank == bankName); - } - - return result; - } + bool hasRelevantBank(HitObject hitObject) => + bankName == HIT_BANK_AUTO + ? enumerateAllSamples(hitObject).SelectMany(o => o).Where(o => o.Name != HitSampleInfo.HIT_NORMAL).All(s => s.EditorAutoBank) + : enumerateAllSamples(hitObject).SelectMany(o => o).Where(o => o.Name != HitSampleInfo.HIT_NORMAL).All(s => s.Bank == bankName && !s.EditorAutoBank); if (SelectedItems.All(hasRelevantBank)) return; EditorBeatmap.PerformOnSelection(h => { - if (enumerateAllSamples(h).SelectMany(o => o).Where(o => o.Name != HitSampleInfo.HIT_NORMAL).All(s => s.Bank == bankName)) + if (hasRelevantBank(h)) return; - h.Samples = h.Samples.Select(s => s.Name != HitSampleInfo.HIT_NORMAL ? s.With(newBank: bankName) : s).ToList(); + string normalBank = h.Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL)?.Bank ?? HitSampleInfo.BANK_SOFT; + h.Samples = h.Samples.Select(s => s.Name != HitSampleInfo.HIT_NORMAL ? bankName == HIT_BANK_AUTO ? s.With(newBank: normalBank, newEditorAutoBank: true) : s.With(newBank: bankName, newEditorAutoBank: false) : s).ToList(); if (h is IHasRepeats hasRepeats) { for (int i = 0; i < hasRepeats.NodeSamples.Count; ++i) - hasRepeats.NodeSamples[i] = hasRepeats.NodeSamples[i].Select(s => s.Name != HitSampleInfo.HIT_NORMAL ? s.With(newBank: bankName) : s).ToList(); + { + normalBank = hasRepeats.NodeSamples[i].FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL)?.Bank ?? HitSampleInfo.BANK_SOFT; + hasRepeats.NodeSamples[i] = hasRepeats.NodeSamples[i].Select(s => s.Name != HitSampleInfo.HIT_NORMAL ? bankName == HIT_BANK_AUTO ? s.With(newBank: normalBank, newEditorAutoBank: true) : s.With(newBank: bankName, newEditorAutoBank: false) : s).ToList(); + } } EditorBeatmap.Update(h); @@ -406,9 +398,9 @@ public void AddHitSample(string sampleName) var hitSample = h.CreateHitSampleInfo(sampleName); - string? existingAdditionBank = node.FirstOrDefault(s => s.Name != HitSampleInfo.HIT_NORMAL)?.Bank; - if (existingAdditionBank != null) - hitSample = hitSample.With(newBank: existingAdditionBank); + HitSampleInfo? existingAddition = node.FirstOrDefault(s => s.Name != HitSampleInfo.HIT_NORMAL); + if (existingAddition != null) + hitSample = hitSample.With(newBank: existingAddition.Bank, newEditorAutoBank: existingAddition.EditorAutoBank); node.Add(hitSample); } diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs index 627609055769..07833694c544 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs @@ -107,7 +107,11 @@ private void updateText() public static string? GetAdditionBankValue(IEnumerable samples) { - return samples.FirstOrDefault(o => o.Name != HitSampleInfo.HIT_NORMAL)?.Bank; + var firstAddition = samples.FirstOrDefault(o => o.Name != HitSampleInfo.HIT_NORMAL); + if (firstAddition == null) + return null; + + return firstAddition.EditorAutoBank ? EditorSelectionHandler.HIT_BANK_AUTO : firstAddition.Bank; } public static int GetVolumeValue(ICollection samples) @@ -320,7 +324,7 @@ private void setBank(string newBank) { for (int i = 0; i < relevantSamples.Count; i++) { - if (relevantSamples[i].Name != HitSampleInfo.HIT_NORMAL) continue; + if (relevantSamples[i].Name != HitSampleInfo.HIT_NORMAL && !relevantSamples[i].EditorAutoBank) continue; relevantSamples[i] = relevantSamples[i].With(newBank: newBank); } @@ -331,11 +335,20 @@ private void setAdditionBank(string newBank) { updateAllRelevantSamples((_, relevantSamples) => { + string normalBank = relevantSamples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL)?.Bank ?? HitSampleInfo.BANK_SOFT; + for (int i = 0; i < relevantSamples.Count; i++) { - if (relevantSamples[i].Name == HitSampleInfo.HIT_NORMAL) continue; + if (relevantSamples[i].Name == HitSampleInfo.HIT_NORMAL) + continue; - relevantSamples[i] = relevantSamples[i].With(newBank: newBank); + // Addition samples with bank set to auto should inherit the bank of the normal sample + if (newBank == EditorSelectionHandler.HIT_BANK_AUTO) + { + relevantSamples[i] = relevantSamples[i].With(newBank: normalBank, newEditorAutoBank: true); + } + else + relevantSamples[i] = relevantSamples[i].With(newBank: newBank, newEditorAutoBank: false); } }); } @@ -383,7 +396,7 @@ private void createStateBindables() selectionSampleStates[sampleName] = bindable; } - banks.AddRange(HitSampleInfo.AllBanks); + banks.AddRange(HitSampleInfo.AllBanks.Prepend(EditorSelectionHandler.HIT_BANK_AUTO)); } private void updateTernaryStates() @@ -448,7 +461,7 @@ protected override bool OnKeyDown(KeyDownEvent e) if (string.IsNullOrEmpty(newBank)) return true; - if (e.ShiftPressed) + if (e.ShiftPressed && newBank != EditorSelectionHandler.HIT_BANK_AUTO) { setBank(newBank); updatePrimaryBankState(); @@ -462,7 +475,7 @@ protected override bool OnKeyDown(KeyDownEvent e) } else { - var item = togglesCollection.ElementAtOrDefault(rightIndex); + var item = togglesCollection.ElementAtOrDefault(rightIndex - 1); if (item is not DrawableTernaryButton button) return base.OnKeyDown(e); @@ -476,18 +489,22 @@ private bool checkRightToggleFromKey(Key key, out int index) { switch (key) { - case Key.W: + case Key.Q: index = 0; break; - case Key.E: + case Key.W: index = 1; break; - case Key.R: + case Key.E: index = 2; break; + case Key.R: + index = 3; + break; + default: index = -1; break; From 861da968d4d3fce9ec40149622e6b2bcba973098 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 1 Oct 2024 16:48:20 +0900 Subject: [PATCH 02/12] Fix banana override --- osu.Game.Rulesets.Catch/Objects/Banana.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Objects/Banana.cs b/osu.Game.Rulesets.Catch/Objects/Banana.cs index b80527f37947..b724c50d0f5a 100644 --- a/osu.Game.Rulesets.Catch/Objects/Banana.cs +++ b/osu.Game.Rulesets.Catch/Objects/Banana.cs @@ -58,7 +58,7 @@ public BananaHitSampleInfo(int volume = 100) { } - public sealed override HitSampleInfo With(Optional newName = default, Optional newBank = default, Optional newSuffix = default, Optional newVolume = default) + public sealed override HitSampleInfo With(Optional newName = default, Optional newBank = default, Optional newSuffix = default, Optional newVolume = default, Optional newEditorAutoBank = default) => new BananaHitSampleInfo(newVolume.GetOr(Volume)); public bool Equals(BananaHitSampleInfo? other) From b741bfb6d9ab98b43374d5fa9df583291804b6b6 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Tue, 1 Oct 2024 11:02:46 +0200 Subject: [PATCH 03/12] Fix TestHotkeysUnifySliderSamplesAndNodeSamples --- .../TestSceneHitObjectSampleAdjustments.cs | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSampleAdjustments.cs b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSampleAdjustments.cs index f0eadf8f9e19..5cc1e6419713 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSampleAdjustments.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSampleAdjustments.cs @@ -739,20 +739,37 @@ public void TestHotkeysUnifySliderSamplesAndNodeSamples() InputManager.ReleaseKey(Key.LShift); }); - hitObjectHasSampleBank(0, HitSampleInfo.BANK_SOFT); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_SOFT); hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_WHISTLE); - hitObjectNodeHasSampleBank(0, 0, HitSampleInfo.BANK_SOFT); + hitObjectNodeHasSampleNormalBank(0, 0, HitSampleInfo.BANK_SOFT); hitObjectNodeHasSamples(0, 0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_CLAP); - hitObjectNodeHasSampleBank(0, 1, HitSampleInfo.BANK_SOFT); + hitObjectNodeHasSampleNormalBank(0, 1, HitSampleInfo.BANK_SOFT); hitObjectNodeHasSamples(0, 1, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_WHISTLE); AddStep("unify whistle addition", () => InputManager.Key(Key.W)); - hitObjectHasSampleBank(0, HitSampleInfo.BANK_SOFT); + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_SOFT); hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_WHISTLE); - hitObjectNodeHasSampleBank(0, 0, HitSampleInfo.BANK_SOFT); + hitObjectNodeHasSampleNormalBank(0, 0, HitSampleInfo.BANK_SOFT); hitObjectNodeHasSamples(0, 0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_CLAP, HitSampleInfo.HIT_WHISTLE); - hitObjectNodeHasSampleBank(0, 1, HitSampleInfo.BANK_SOFT); + hitObjectNodeHasSampleNormalBank(0, 1, HitSampleInfo.BANK_SOFT); + hitObjectNodeHasSamples(0, 1, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_WHISTLE); + + AddStep("set drum addition bank", () => + { + InputManager.PressKey(Key.LAlt); + InputManager.Key(Key.R); + InputManager.ReleaseKey(Key.LAlt); + }); + + hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_SOFT); + hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_DRUM); + hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_WHISTLE); + hitObjectNodeHasSampleNormalBank(0, 0, HitSampleInfo.BANK_SOFT); + hitObjectNodeHasSampleAdditionBank(0, 0, HitSampleInfo.BANK_DRUM); + hitObjectNodeHasSamples(0, 0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_CLAP, HitSampleInfo.HIT_WHISTLE); + hitObjectNodeHasSampleNormalBank(0, 1, HitSampleInfo.BANK_SOFT); + hitObjectNodeHasSampleAdditionBank(0, 1, HitSampleInfo.BANK_DRUM); hitObjectNodeHasSamples(0, 1, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_WHISTLE); } From 6be94a3a964d6edc606f4b7bb2b63f0d26775bc4 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Tue, 1 Oct 2024 11:13:44 +0200 Subject: [PATCH 04/12] Fix TestSplitRetainsHitsounds --- osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs index d68cbe6265d1..d5bacc25bce6 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs @@ -180,7 +180,7 @@ public void TestSplitRetainsHitsounds() { if (slider == null) return; - sample = new HitSampleInfo("hitwhistle", HitSampleInfo.BANK_SOFT, volume: 70); + sample = new HitSampleInfo("hitwhistle", HitSampleInfo.BANK_SOFT, volume: 70, editorAutoBank: false); slider.Samples.Add(sample.With()); }); From 2381c2c72c1f59f73ba8d4bf17818ab8197b4e62 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Tue, 1 Oct 2024 12:11:44 +0200 Subject: [PATCH 05/12] Fix hitobjects without custom sample banks parsing as not auto sample bank --- osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index fa3ee41b4747..89fd5f73846e 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -543,7 +543,7 @@ private class SampleBankInfo /// /// Whether the bank for additions should be inherited from the normal sample in edit. /// - public bool EditorAutoBank; + public bool EditorAutoBank = true; public SampleBankInfo Clone() => (SampleBankInfo)MemberwiseClone(); } From 1960a0d44dab6aa0e3ad9bc3fdfa6c5eb3e1c11d Mon Sep 17 00:00:00 2001 From: OliBomby Date: Tue, 1 Oct 2024 13:07:25 +0200 Subject: [PATCH 06/12] Add tooltip to explain why addition banks dont work when no additions exist --- .../Components/TernaryButtons/DrawableTernaryButton.cs | 6 +++++- .../Edit/Components/TernaryButtons/TernaryButton.cs | 2 ++ .../Edit/Compose/Components/ComposeBlueprintContainer.cs | 8 ++++++++ .../Edit/Compose/Components/EditorSelectionHandler.cs | 7 +++++++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs b/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs index 9e528aa21b4b..7a9bdfc41f5b 100644 --- a/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs +++ b/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs @@ -4,8 +4,10 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; @@ -14,7 +16,7 @@ namespace osu.Game.Screens.Edit.Components.TernaryButtons { - public partial class DrawableTernaryButton : OsuButton + public partial class DrawableTernaryButton : OsuButton, IHasTooltip { private Color4 defaultBackgroundColour; private Color4 defaultIconColour; @@ -98,5 +100,7 @@ private void updateSelectionState() Anchor = Anchor.CentreLeft, X = 40f }; + + public LocalisableString TooltipText => Button.Tooltip; } } diff --git a/osu.Game/Screens/Edit/Components/TernaryButtons/TernaryButton.cs b/osu.Game/Screens/Edit/Components/TernaryButtons/TernaryButton.cs index 0ff2aa83b5ca..b025e4fbf5c2 100644 --- a/osu.Game/Screens/Edit/Components/TernaryButtons/TernaryButton.cs +++ b/osu.Game/Screens/Edit/Components/TernaryButtons/TernaryButton.cs @@ -19,6 +19,8 @@ public class TernaryButton /// public readonly Func? CreateIcon; + public string Tooltip { get; set; } = string.Empty; + public TernaryButton(Bindable bindable, string description, Func? createIcon = null) { Bindable = bindable; diff --git a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs index 76e35a35c6c6..bfa6da8c7c1c 100644 --- a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs @@ -68,6 +68,8 @@ private void load() SampleBankTernaryStates = createSampleBankTernaryButtons(SelectionHandler.SelectionBankStates).ToArray(); SampleAdditionBankTernaryStates = createSampleBankTernaryButtons(SelectionHandler.SelectionAdditionBankStates).ToArray(); + SelectionHandler.SelectionAdditionBanksEnabled.BindValueChanged(_ => updateTernaryButtonTooltips()); + AddInternal(new DrawableRulesetDependenciesProvidingContainer(Composer.Ruleset) { Child = placementBlueprintContainer @@ -288,6 +290,12 @@ public static Drawable GetIconForSample(string sampleName) return null; } + private void updateTernaryButtonTooltips() + { + foreach (var ternaryButton in SampleAdditionBankTernaryStates) + ternaryButton.Tooltip = !SelectionHandler.SelectionAdditionBanksEnabled.Value ? "Add an addition sample first to be able to set a bank" : string.Empty; + } + #region Placement /// diff --git a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs index 8de3f3052f97..a68d3afef8a6 100644 --- a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs @@ -63,6 +63,11 @@ private void load() /// public readonly Dictionary> SelectionAdditionBankStates = new Dictionary>(); + /// + /// Whether the selection contains any addition samples and the can be used. + /// + public readonly Bindable SelectionAdditionBanksEnabled = new Bindable(); + /// /// Set up ternary state bindables and bind them to selection/hitobject changes (in both directions) /// @@ -266,6 +271,8 @@ protected virtual void UpdateTernaryStates() bindable.Value = GetStateFromSelection(samplesInSelection.SelectMany(s => s).Where(o => o.Name == HitSampleInfo.HIT_NORMAL), h => h.Bank == bankName); } + SelectionAdditionBanksEnabled.Value = samplesInSelection.SelectMany(s => s).Any(o => o.Name != HitSampleInfo.HIT_NORMAL); + foreach ((string bankName, var bindable) in SelectionAdditionBankStates) { bindable.Value = GetStateFromSelection(samplesInSelection.SelectMany(s => s).Where(o => o.Name != HitSampleInfo.HIT_NORMAL), h => (bankName != HIT_BANK_AUTO && h.Bank == bankName && !h.EditorAutoBank) || (bankName == HIT_BANK_AUTO && h.EditorAutoBank)); From 154a3eebc666a7856aaaecbacb72c2ded417aebd Mon Sep 17 00:00:00 2001 From: OliBomby Date: Tue, 1 Oct 2024 13:22:20 +0200 Subject: [PATCH 07/12] Reset the sample bank states to auto when selection is cleared this matches behaviour in stable --- .../Components/EditorSelectionHandler.cs | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs index a68d3afef8a6..c30a4186525c 100644 --- a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs @@ -3,13 +3,13 @@ using System; using System.Collections.Generic; +using System.Collections.Specialized; using System.Linq; using Humanizer; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.UserInterface; using osu.Game.Audio; -using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; @@ -36,7 +36,7 @@ private void load() // bring in updates from selection changes EditorBeatmap.HitObjectUpdated += _ => Scheduler.AddOnce(UpdateTernaryStates); - SelectedItems.CollectionChanged += (_, _) => Scheduler.AddOnce(UpdateTernaryStates); + SelectedItems.CollectionChanged += onSelectedItemsChanged; } protected override void DeleteItems(IEnumerable items) => EditorBeatmap.RemoveRange(items); @@ -208,9 +208,7 @@ private void createStateBindables() SelectionAdditionBankStates[bankName] = bindable; } - // start with normal selected. - SelectionBankStates[SampleControlPoint.DEFAULT_BANK].Value = TernaryState.True; - SelectionAdditionBankStates[HIT_BANK_AUTO].Value = TernaryState.True; + resetTernaryStates(); foreach (string sampleName in HitSampleInfo.AllAdditions) { @@ -252,6 +250,12 @@ private void createStateBindables() }; } + private void resetTernaryStates() + { + SelectionBankStates[HIT_BANK_AUTO].Value = TernaryState.True; + SelectionAdditionBankStates[HIT_BANK_AUTO].Value = TernaryState.True; + } + /// /// Called when context menu ternary states may need to be recalculated (selection changed or hitobject updated). /// @@ -279,6 +283,15 @@ protected virtual void UpdateTernaryStates() } } + private void onSelectedItemsChanged(object? sender, NotifyCollectionChangedEventArgs e) + { + // Reset the ternary states when the selection is cleared. + if (e.OldStartingIndex >= 0 && e.NewStartingIndex < 0) + Scheduler.AddOnce(resetTernaryStates); + else + Scheduler.AddOnce(UpdateTernaryStates); + } + private IEnumerable> enumerateAllSamples(HitObject hitObject) { yield return hitObject.Samples; From ddbeb56f0f92544ee5463c94e4e6b3f69fe8d406 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Wed, 23 Oct 2024 21:25:37 +0200 Subject: [PATCH 08/12] Show tooltip on auto normal bank when not usable --- .../Compose/Components/ComposeBlueprintContainer.cs | 11 +++++++++-- .../Edit/Compose/Components/EditorSelectionHandler.cs | 7 +++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs index fe9a6e644332..4331199a4782 100644 --- a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs @@ -68,7 +68,8 @@ private void load() SampleBankTernaryStates = createSampleBankTernaryButtons(SelectionHandler.SelectionBankStates).ToArray(); SampleAdditionBankTernaryStates = createSampleBankTernaryButtons(SelectionHandler.SelectionAdditionBankStates).ToArray(); - SelectionHandler.SelectionAdditionBanksEnabled.BindValueChanged(_ => updateTernaryButtonTooltips()); + SelectionHandler.AutoSelectionBankEnabled.BindValueChanged(_ => updateAutoBankTernaryButtonTooltip(), true); + SelectionHandler.SelectionAdditionBanksEnabled.BindValueChanged(_ => updateAdditionBankTernaryButtonTooltips(), true); AddInternal(new DrawableRulesetDependenciesProvidingContainer(Composer.Ruleset) { @@ -290,7 +291,13 @@ public static Drawable GetIconForSample(string sampleName) return null; } - private void updateTernaryButtonTooltips() + private void updateAutoBankTernaryButtonTooltip() + { + var autoBankButton = SampleBankTernaryStates.Single(t => t.Bindable == SelectionHandler.SelectionBankStates[EditorSelectionHandler.HIT_BANK_AUTO]); + autoBankButton.Tooltip = !SelectionHandler.AutoSelectionBankEnabled.Value ? "Auto normal bank can only be used during hit object placement" : string.Empty; + } + + private void updateAdditionBankTernaryButtonTooltips() { foreach (var ternaryButton in SampleAdditionBankTernaryStates) ternaryButton.Tooltip = !SelectionHandler.SelectionAdditionBanksEnabled.Value ? "Add an addition sample first to be able to set a bank" : string.Empty; diff --git a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs index beead572e601..2d5341e85e35 100644 --- a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs @@ -64,6 +64,11 @@ private void load() /// public readonly Dictionary> SelectionAdditionBankStates = new Dictionary>(); + /// + /// Whether there is no selection and the auto can be used. + /// + public readonly Bindable AutoSelectionBankEnabled = new Bindable(); + /// /// Whether the selection contains any addition samples and the can be used. /// @@ -253,6 +258,7 @@ private void createStateBindables() private void resetTernaryStates() { + AutoSelectionBankEnabled.Value = true; SelectionBankStates[HIT_BANK_AUTO].Value = TernaryState.True; SelectionAdditionBankStates[HIT_BANK_AUTO].Value = TernaryState.True; } @@ -263,6 +269,7 @@ private void resetTernaryStates() protected virtual void UpdateTernaryStates() { SelectionNewComboState.Value = GetStateFromSelection(SelectedItems.OfType(), h => h.NewCombo); + AutoSelectionBankEnabled.Value = SelectedItems.Count == 0; var samplesInSelection = SelectedItems.SelectMany(enumerateAllSamples).ToArray(); From 77bd0e8d7004f0b9c237a5377c24882b36c09bab Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Oct 2024 18:36:34 +0900 Subject: [PATCH 09/12] Add visual disabled state to ternary buttons --- .../TernaryButtons/DrawableTernaryButton.cs | 3 +++ .../Edit/Components/TernaryButtons/TernaryButton.cs | 2 ++ .../Compose/Components/ComposeBlueprintContainer.cs | 12 ++++++++++-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs b/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs index 7a9bdfc41f5b..aedae9fea14a 100644 --- a/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs +++ b/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs @@ -66,6 +66,9 @@ protected override void LoadComplete() private void onAction() { + if (!Button.Enabled.Value) + return; + Button.Toggle(); } diff --git a/osu.Game/Screens/Edit/Components/TernaryButtons/TernaryButton.cs b/osu.Game/Screens/Edit/Components/TernaryButtons/TernaryButton.cs index b025e4fbf5c2..8d1bc8d9fc6a 100644 --- a/osu.Game/Screens/Edit/Components/TernaryButtons/TernaryButton.cs +++ b/osu.Game/Screens/Edit/Components/TernaryButtons/TernaryButton.cs @@ -12,6 +12,8 @@ public class TernaryButton { public readonly Bindable Bindable; + public readonly Bindable Enabled = new Bindable(); + public readonly string Description; /// diff --git a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs index 4331199a4782..69e676667d8f 100644 --- a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs @@ -293,14 +293,22 @@ public static Drawable GetIconForSample(string sampleName) private void updateAutoBankTernaryButtonTooltip() { + bool enabled = SelectionHandler.AutoSelectionBankEnabled.Value; + var autoBankButton = SampleBankTernaryStates.Single(t => t.Bindable == SelectionHandler.SelectionBankStates[EditorSelectionHandler.HIT_BANK_AUTO]); - autoBankButton.Tooltip = !SelectionHandler.AutoSelectionBankEnabled.Value ? "Auto normal bank can only be used during hit object placement" : string.Empty; + autoBankButton.Enabled.Value = enabled; + autoBankButton.Tooltip = !enabled ? "Auto normal bank can only be used during hit object placement" : string.Empty; } private void updateAdditionBankTernaryButtonTooltips() { + bool enabled = SelectionHandler.SelectionAdditionBanksEnabled.Value; + foreach (var ternaryButton in SampleAdditionBankTernaryStates) - ternaryButton.Tooltip = !SelectionHandler.SelectionAdditionBanksEnabled.Value ? "Add an addition sample first to be able to set a bank" : string.Empty; + { + ternaryButton.Enabled.Value = enabled; + ternaryButton.Tooltip = !enabled ? "Add an addition sample first to be able to set a bank" : string.Empty; + } } #region Placement From 940220b64942cb32e541649d90697625814385d9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Oct 2024 19:57:39 +0900 Subject: [PATCH 10/12] Fix big oops --- .../Screens/Edit/Components/TernaryButtons/TernaryButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Components/TernaryButtons/TernaryButton.cs b/osu.Game/Screens/Edit/Components/TernaryButtons/TernaryButton.cs index 8d1bc8d9fc6a..b7aaf517f57a 100644 --- a/osu.Game/Screens/Edit/Components/TernaryButtons/TernaryButton.cs +++ b/osu.Game/Screens/Edit/Components/TernaryButtons/TernaryButton.cs @@ -12,7 +12,7 @@ public class TernaryButton { public readonly Bindable Bindable; - public readonly Bindable Enabled = new Bindable(); + public readonly Bindable Enabled = new Bindable(true); public readonly string Description; From 5b92a9ff595cbbc5c42f1f3d95d94c1c1c05f7ed Mon Sep 17 00:00:00 2001 From: OliBomby Date: Thu, 24 Oct 2024 13:15:09 +0200 Subject: [PATCH 11/12] Fix enabled state not updating drawable --- .../Edit/Components/TernaryButtons/DrawableTernaryButton.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs b/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs index aedae9fea14a..fcbc719f4637 100644 --- a/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs +++ b/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs @@ -60,6 +60,7 @@ protected override void LoadComplete() base.LoadComplete(); Button.Bindable.BindValueChanged(_ => updateSelectionState(), true); + Button.Enabled.BindTo(Enabled); Action = onAction; } From 88e88bdc4fcffe920c1f95f8592eaa9da2fe1624 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Thu, 24 Oct 2024 13:17:49 +0200 Subject: [PATCH 12/12] Fix addition banks disabled on reset --- .../Screens/Edit/Compose/Components/EditorSelectionHandler.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs index 2d5341e85e35..ca774c34e76d 100644 --- a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs @@ -259,6 +259,7 @@ private void createStateBindables() private void resetTernaryStates() { AutoSelectionBankEnabled.Value = true; + SelectionAdditionBanksEnabled.Value = true; SelectionBankStates[HIT_BANK_AUTO].Value = TernaryState.True; SelectionAdditionBankStates[HIT_BANK_AUTO].Value = TernaryState.True; }