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

Include node samples when changing additions and banks #28711

Merged
merged 2 commits into from
Jul 3, 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
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,88 @@ public void TestHotkeysDuringPlacement()
void checkPlacementSample(string expected) => AddAssert($"Placement sample is {expected}", () => EditorBeatmap.PlacementObject.Value.Samples.First().Bank, () => Is.EqualTo(expected));
}

[Test]
public void TestHotkeysAffectNodeSamples()
{
AddStep("add slider", () =>
{
EditorBeatmap.Add(new Slider
{
Position = new Vector2(256, 256),
StartTime = 1000,
Path = new SliderPath(new[] { new PathControlPoint(Vector2.Zero), new PathControlPoint(new Vector2(250, 0)) }),
Samples =
{
new HitSampleInfo(HitSampleInfo.HIT_NORMAL)
},
NodeSamples = new List<IList<HitSampleInfo>>
{
new List<HitSampleInfo>
{
new HitSampleInfo(HitSampleInfo.HIT_NORMAL, bank: HitSampleInfo.BANK_DRUM),
new HitSampleInfo(HitSampleInfo.HIT_CLAP, bank: HitSampleInfo.BANK_DRUM),
},
new List<HitSampleInfo>
{
new HitSampleInfo(HitSampleInfo.HIT_NORMAL, bank: HitSampleInfo.BANK_SOFT),
new HitSampleInfo(HitSampleInfo.HIT_WHISTLE, bank: HitSampleInfo.BANK_SOFT),
},
}
});
});
AddStep("select everything", () => EditorBeatmap.SelectedHitObjects.AddRange(EditorBeatmap.HitObjects));

AddStep("add clap addition", () => InputManager.Key(Key.R));

hitObjectHasSampleBank(0, HitSampleInfo.BANK_NORMAL);
hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_CLAP);

hitObjectHasSampleBank(1, HitSampleInfo.BANK_SOFT);
hitObjectHasSamples(1, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_CLAP);

hitObjectHasSampleBank(2, HitSampleInfo.BANK_NORMAL);
hitObjectHasSamples(2, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_CLAP);
hitObjectNodeHasSampleBank(2, 0, HitSampleInfo.BANK_DRUM);
hitObjectNodeHasSamples(2, 0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_CLAP);
hitObjectNodeHasSampleBank(2, 1, HitSampleInfo.BANK_SOFT);
hitObjectNodeHasSamples(2, 1, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_WHISTLE, HitSampleInfo.HIT_CLAP);

AddStep("remove clap addition", () => InputManager.Key(Key.R));

hitObjectHasSampleBank(0, HitSampleInfo.BANK_NORMAL);
hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL);

hitObjectHasSampleBank(1, HitSampleInfo.BANK_SOFT);
hitObjectHasSamples(1, HitSampleInfo.HIT_NORMAL);

hitObjectHasSampleBank(2, HitSampleInfo.BANK_NORMAL);
hitObjectHasSamples(2, HitSampleInfo.HIT_NORMAL);
hitObjectNodeHasSampleBank(2, 0, HitSampleInfo.BANK_DRUM);
hitObjectNodeHasSamples(2, 0, HitSampleInfo.HIT_NORMAL);
hitObjectNodeHasSampleBank(2, 1, HitSampleInfo.BANK_SOFT);
hitObjectNodeHasSamples(2, 1, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_WHISTLE);

AddStep("set drum bank", () =>
{
InputManager.PressKey(Key.LShift);
InputManager.Key(Key.R);
InputManager.ReleaseKey(Key.LShift);
});

hitObjectHasSampleBank(0, HitSampleInfo.BANK_DRUM);
hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL);

hitObjectHasSampleBank(1, HitSampleInfo.BANK_DRUM);
hitObjectHasSamples(1, HitSampleInfo.HIT_NORMAL);

hitObjectHasSampleBank(2, HitSampleInfo.BANK_DRUM);
hitObjectHasSamples(2, HitSampleInfo.HIT_NORMAL);
hitObjectNodeHasSampleBank(2, 0, HitSampleInfo.BANK_DRUM);
hitObjectNodeHasSamples(2, 0, HitSampleInfo.HIT_NORMAL);
hitObjectNodeHasSampleBank(2, 1, HitSampleInfo.BANK_DRUM);
hitObjectNodeHasSamples(2, 1, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_WHISTLE);
}

private void clickSamplePiece(int objectIndex) => AddStep($"click {objectIndex.ToOrdinalWords()} sample piece", () =>
{
var samplePiece = this.ChildrenOfType<SamplePointPiece>().Single(piece => piece.HitObject == EditorBeatmap.HitObjects.ElementAt(objectIndex));
Expand Down
86 changes: 78 additions & 8 deletions osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ private void createStateBindables()
break;
}

AddSampleBank(bankName);
SetSampleBank(bankName);
}

break;
Expand Down Expand Up @@ -177,14 +177,27 @@ protected virtual void UpdateTernaryStates()
{
SelectionNewComboState.Value = GetStateFromSelection(SelectedItems.OfType<IHasComboInformation>(), h => h.NewCombo);

var samplesInSelection = SelectedItems.SelectMany(enumerateAllSamples).ToArray();

foreach ((string sampleName, var bindable) in SelectionSampleStates)
{
bindable.Value = GetStateFromSelection(SelectedItems, h => h.Samples.Any(s => s.Name == sampleName));
bindable.Value = GetStateFromSelection(samplesInSelection, h => h.Any(s => s.Name == sampleName));
}

foreach ((string bankName, var bindable) in SelectionBankStates)
{
bindable.Value = GetStateFromSelection(SelectedItems, h => h.Samples.All(s => s.Bank == bankName));
bindable.Value = GetStateFromSelection(samplesInSelection, h => h.Any(s => s.Bank == bankName));
}

IEnumerable<IList<HitSampleInfo>> enumerateAllSamples(HitObject hitObject)
{
yield return hitObject.Samples;

if (hitObject is IHasRepeats withRepeats)
{
foreach (var node in withRepeats.NodeSamples)
yield return node;
}
}
}

Expand All @@ -193,12 +206,25 @@ protected virtual void UpdateTernaryStates()
#region Ternary state changes

/// <summary>
/// Adds a sample bank to all selected <see cref="HitObject"/>s.
/// Sets the sample bank for all selected <see cref="HitObject"/>s.
/// </summary>
/// <param name="bankName">The name of the sample bank.</param>
public void AddSampleBank(string bankName)
public void SetSampleBank(string bankName)
{
if (SelectedItems.All(h => h.Samples.All(s => s.Bank == bankName)))
bool hasRelevantBank(HitObject hitObject)
{
bool result = hitObject.Samples.All(s => s.Bank == bankName);

if (hitObject is IHasRepeats hasRepeats)
{
foreach (var node in hasRepeats.NodeSamples)
result &= node.All(s => s.Bank == bankName);
}

return result;
}

if (SelectedItems.All(hasRelevantBank))
return;

EditorBeatmap.PerformOnSelection(h =>
Expand All @@ -207,17 +233,37 @@ public void AddSampleBank(string bankName)
return;

h.Samples = h.Samples.Select(s => s.With(newBank: bankName)).ToList();

if (h is IHasRepeats hasRepeats)
{
for (int i = 0; i < hasRepeats.NodeSamples.Count; ++i)
hasRepeats.NodeSamples[i] = hasRepeats.NodeSamples[i].Select(s => s.With(newBank: bankName)).ToList();
}

EditorBeatmap.Update(h);
});
}

private bool hasRelevantSample(HitObject hitObject, string sampleName)
{
bool result = hitObject.Samples.Any(s => s.Name == sampleName);

if (hitObject is IHasRepeats hasRepeats)
{
foreach (var node in hasRepeats.NodeSamples)
result &= node.Any(s => s.Name == sampleName);
}

return result;
}

/// <summary>
/// Adds a hit sample to all selected <see cref="HitObject"/>s.
/// </summary>
/// <param name="sampleName">The name of the hit sample.</param>
public void AddHitSample(string sampleName)
{
if (SelectedItems.All(h => h.Samples.Any(s => s.Name == sampleName)))
if (SelectedItems.All(h => hasRelevantSample(h, sampleName)))
return;

EditorBeatmap.PerformOnSelection(h =>
Expand All @@ -228,6 +274,23 @@ public void AddHitSample(string sampleName)

h.Samples.Add(h.CreateHitSampleInfo(sampleName));

if (h is IHasRepeats hasRepeats)
{
foreach (var node in hasRepeats.NodeSamples)
{
if (node.Any(s => s.Name == sampleName))
continue;

var hitSample = h.CreateHitSampleInfo(sampleName);

string? existingAdditionBank = node.FirstOrDefault(s => s.Name != HitSampleInfo.HIT_NORMAL)?.Bank;
if (existingAdditionBank != null)
hitSample = hitSample.With(newBank: existingAdditionBank);

node.Add(hitSample);
}
}

EditorBeatmap.Update(h);
});
}
Expand All @@ -238,12 +301,19 @@ public void AddHitSample(string sampleName)
/// <param name="sampleName">The name of the hit sample.</param>
public void RemoveHitSample(string sampleName)
{
if (SelectedItems.All(h => h.Samples.All(s => s.Name != sampleName)))
if (SelectedItems.All(h => !hasRelevantSample(h, sampleName)))
return;

EditorBeatmap.PerformOnSelection(h =>
{
h.SamplesBindable.RemoveAll(s => s.Name == sampleName);

if (h is IHasRepeats hasRepeats)
{
for (int i = 0; i < hasRepeats.NodeSamples.Count; ++i)
hasRepeats.NodeSamples[i] = hasRepeats.NodeSamples[i].Where(s => s.Name != sampleName).ToList();
}

EditorBeatmap.Update(h);
});
}
Expand Down
Loading