Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for the auto sample addition bank in the editor #29648

Merged
merged 14 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion osu.Game.Rulesets.Catch/Objects/Banana.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public BananaHitSampleInfo(int volume = 100)
{
}

public sealed override HitSampleInfo With(Optional<string> newName = default, Optional<string> newBank = default, Optional<string?> newSuffix = default, Optional<int> newVolume = default)
public sealed override HitSampleInfo With(Optional<string> newName = default, Optional<string> newBank = default, Optional<string?> newSuffix = default, Optional<int> newVolume = default, Optional<bool> newEditorAutoBank = default)
=> new BananaHitSampleInfo(newVolume.GetOr(Volume));

public bool Equals(BananaHitSampleInfo? other)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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());
});

Expand Down
13 changes: 10 additions & 3 deletions osu.Game/Audio/HitSampleInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,18 @@ public class HitSampleInfo : ISampleInfo, IEquatable<HitSampleInfo>
/// </summary>
public int Volume { get; }

public HitSampleInfo(string name, string bank = SampleControlPoint.DEFAULT_BANK, string? suffix = null, int volume = 100)
/// <summary>
/// Whether this sample should automatically assign the bank of the normal sample whenever it is set in the editor.
/// </summary>
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;
}

/// <summary>
Expand All @@ -92,9 +98,10 @@ public virtual IEnumerable<string> LookupNames
/// <param name="newBank">An optional new sample bank.</param>
/// <param name="newSuffix">An optional new lookup suffix.</param>
/// <param name="newVolume">An optional new volume.</param>
/// <param name="newEditorAutoBank">An optional new editor auto bank flag.</param>
/// <returns>The new <see cref="HitSampleInfo"/>.</returns>
public virtual HitSampleInfo With(Optional<string> newName = default, Optional<string> newBank = default, Optional<string?> newSuffix = default, Optional<int> newVolume = default)
=> new HitSampleInfo(newName.GetOr(Name), newBank.GetOr(Bank), newSuffix.GetOr(Suffix), newVolume.GetOr(Volume));
public virtual HitSampleInfo With(Optional<string> newName = default, Optional<string> newBank = default, Optional<string?> newSuffix = default, Optional<int> newVolume = default, Optional<bool> 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;
Expand Down
2 changes: 1 addition & 1 deletion osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ private void addEndTimeData(TextWriter writer, HitObject hitObject)
private string getSampleBank(IList<HitSampleInfo> 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();

Expand Down
2 changes: 1 addition & 1 deletion osu.Game/Rulesets/Objects/HitObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
33 changes: 22 additions & 11 deletions osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -477,7 +483,7 @@ private List<HitSampleInfo> 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)));
Expand All @@ -489,13 +495,13 @@ private List<HitSampleInfo> 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;
}
Expand Down Expand Up @@ -534,6 +540,11 @@ private class SampleBankInfo
/// </summary>
public int CustomSampleBank;

/// <summary>
/// Whether the bank for additions should be inherited from the normal sample in edit.
/// </summary>
public bool EditorAutoBank = true;

public SampleBankInfo Clone() => (SampleBankInfo)MemberwiseClone();
}

Expand All @@ -558,21 +569,21 @@ public class LegacyHitSampleInfo : HitSampleInfo, IEquatable<LegacyHitSampleInfo
/// </summary>
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<string> newName = default, Optional<string> newBank = default, Optional<string?> newSuffix = default, Optional<int> newVolume = default)
=> With(newName, newBank, newVolume);
public sealed override HitSampleInfo With(Optional<string> newName = default, Optional<string> newBank = default, Optional<string?> newSuffix = default, Optional<int> newVolume = default, Optional<bool> newEditorAutoBank = default)
=> With(newName, newBank, newVolume, newEditorAutoBank);

public virtual LegacyHitSampleInfo With(Optional<string> newName = default, Optional<string> newBank = default, Optional<int> newVolume = default,
public virtual LegacyHitSampleInfo With(Optional<string> newName = default, Optional<string> newBank = default, Optional<int> newVolume = default, Optional<bool> newEditorAutoBank = default,
Optional<int> newCustomSampleBank = default,
Optional<bool> 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.
Expand Down Expand Up @@ -604,7 +615,7 @@ public FileHitSampleInfo(string filename, int volume)
Path.ChangeExtension(Filename, null)
};

public sealed override LegacyHitSampleInfo With(Optional<string> newName = default, Optional<string> newBank = default, Optional<int> newVolume = default,
public sealed override LegacyHitSampleInfo With(Optional<string> newName = default, Optional<string> newBank = default, Optional<int> newVolume = default, Optional<bool> newEditorAutoBank = default,
Optional<int> newCustomSampleBank = default,
Optional<bool> newIsLayered = default)
=> new FileHitSampleInfo(Filename, newVolume.GetOr(Volume));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -58,12 +60,16 @@ protected override void LoadComplete()
base.LoadComplete();

Button.Bindable.BindValueChanged(_ => updateSelectionState(), true);
Button.Enabled.BindTo(Enabled);

Action = onAction;
}

private void onAction()
{
if (!Button.Enabled.Value)
return;

Button.Toggle();
}

Expand Down Expand Up @@ -98,5 +104,7 @@ private void updateSelectionState()
Anchor = Anchor.CentreLeft,
X = 40f
};

public LocalisableString TooltipText => Button.Tooltip;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,17 @@ public class TernaryButton
{
public readonly Bindable<TernaryState> Bindable;

public readonly Bindable<bool> Enabled = new Bindable<bool>(true);

public readonly string Description;

/// <summary>
/// A function which creates a drawable icon to represent this item. If null, a sane default should be used.
/// </summary>
public readonly Func<Drawable>? CreateIcon;

public string Tooltip { get; set; } = string.Empty;

public TernaryButton(Bindable<TernaryState> bindable, string description, Func<Drawable>? createIcon = null)
{
Bindable = bindable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ private void load()
SampleBankTernaryStates = createSampleBankTernaryButtons(SelectionHandler.SelectionBankStates).ToArray();
SampleAdditionBankTernaryStates = createSampleBankTernaryButtons(SelectionHandler.SelectionAdditionBankStates).ToArray();

SelectionHandler.AutoSelectionBankEnabled.BindValueChanged(_ => updateAutoBankTernaryButtonTooltip(), true);
SelectionHandler.SelectionAdditionBanksEnabled.BindValueChanged(_ => updateAdditionBankTernaryButtonTooltips(), true);

AddInternal(new DrawableRulesetDependenciesProvidingContainer(Composer.Ruleset)
{
Child = placementBlueprintContainer
Expand Down Expand Up @@ -288,6 +291,26 @@ public static Drawable GetIconForSample(string sampleName)
return null;
}

private void updateAutoBankTernaryButtonTooltip()
{
bool enabled = SelectionHandler.AutoSelectionBankEnabled.Value;

var autoBankButton = SampleBankTernaryStates.Single(t => t.Bindable == SelectionHandler.SelectionBankStates[EditorSelectionHandler.HIT_BANK_AUTO]);
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.Enabled.Value = enabled;
ternaryButton.Tooltip = !enabled ? "Add an addition sample first to be able to set a bank" : string.Empty;
}
}

#region Placement

/// <summary>
Expand Down
Loading
Loading