mirror of
https://github.com/ppy/osu.git
synced 2025-02-21 03:02:54 +08:00
Merge pull request #28619 from bdach/fix-tail-volume-not-saving
Fix slider tail volume not saving
This commit is contained in:
commit
537e3a1642
@ -528,8 +528,17 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
Assert.AreEqual("Gameplay/normal-hitnormal2", getTestableSampleInfo(hitObjects[2]).LookupNames.First());
|
||||
Assert.AreEqual("Gameplay/normal-hitnormal", getTestableSampleInfo(hitObjects[3]).LookupNames.First());
|
||||
|
||||
// The control point at the end time of the slider should be applied
|
||||
Assert.AreEqual("Gameplay/soft-hitnormal8", getTestableSampleInfo(hitObjects[4]).LookupNames.First());
|
||||
// The fourth object is a slider.
|
||||
// `Samples` of a slider are presumed to control the volume of sounds that last the entire duration of the slider
|
||||
// (such as ticks, slider slide sounds, etc.)
|
||||
// Thus, the point of query of control points used for `Samples` is just beyond the start time of the slider.
|
||||
Assert.AreEqual("Gameplay/soft-hitnormal11", getTestableSampleInfo(hitObjects[4]).LookupNames.First());
|
||||
|
||||
// That said, the `NodeSamples` of the slider are responsible for the sounds of the slider's head / tail / repeats / large ticks etc.
|
||||
// Therefore, they should be read at the time instant correspondent to the given node.
|
||||
// This means that the tail should use bank 8 rather than 11.
|
||||
Assert.AreEqual("Gameplay/soft-hitnormal11", ((ConvertSlider)hitObjects[4]).NodeSamples[0][0].LookupNames.First());
|
||||
Assert.AreEqual("Gameplay/soft-hitnormal8", ((ConvertSlider)hitObjects[4]).NodeSamples[1][0].LookupNames.First());
|
||||
}
|
||||
|
||||
static HitSampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.Samples[0];
|
||||
|
22
osu.Game.Tests/Resources/per-slider-node-sample-settings.osu
Normal file
22
osu.Game.Tests/Resources/per-slider-node-sample-settings.osu
Normal file
@ -0,0 +1,22 @@
|
||||
osu file format v128
|
||||
|
||||
[General]
|
||||
SampleSet: Normal
|
||||
|
||||
[TimingPoints]
|
||||
15,1000,4,1,0,100,1,0
|
||||
2271,-100,4,1,0,5,0,0
|
||||
6021,-100,4,1,0,100,0,0
|
||||
8515,-100,4,1,0,5,0,0
|
||||
12765,-100,4,1,0,100,0,0
|
||||
14764,-100,4,1,0,5,0,0
|
||||
14770,-100,4,1,0,50,0,0
|
||||
17264,-100,4,1,0,5,0,0
|
||||
17270,-100,4,1,0,50,0,0
|
||||
22264,-100,4,1,0,100,0,0
|
||||
|
||||
[HitObjects]
|
||||
113,54,2265,6,0,L|422:55,1,300,0|0,1:0|1:0,1:0:0:0:
|
||||
82,206,6015,2,0,L|457:204,1,350,0|0,2:0|2:0,2:0:0:0:
|
||||
75,310,10265,2,0,L|435:312,1,350,0|0,3:0|3:0,3:0:0:0:
|
||||
75,310,14764,2,0,L|435:312,3,350,0|0|0|0,3:0|3:0|3:0|3:0,3:0:0:0:
|
@ -32,7 +32,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
/// <remarks>
|
||||
/// Compare: https://github.com/peppy/osu-stable-reference/blob/master/osu!/GameplayElements/HitObjects/HitObject.cs#L319
|
||||
/// </remarks>
|
||||
private const double control_point_leniency = 5;
|
||||
public const double CONTROL_POINT_LENIENCY = 5;
|
||||
|
||||
internal static RulesetStore? RulesetStore;
|
||||
|
||||
@ -159,20 +159,24 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
private void applySamples(HitObject hitObject)
|
||||
{
|
||||
SampleControlPoint sampleControlPoint = (beatmap.ControlPointInfo as LegacyControlPointInfo)?.SamplePointAt(hitObject.GetEndTime() + control_point_leniency) ?? SampleControlPoint.DEFAULT;
|
||||
|
||||
hitObject.Samples = hitObject.Samples.Select(o => sampleControlPoint.ApplyTo(o)).ToList();
|
||||
|
||||
if (hitObject is IHasRepeats hasRepeats)
|
||||
{
|
||||
SampleControlPoint sampleControlPoint = (beatmap.ControlPointInfo as LegacyControlPointInfo)?.SamplePointAt(hitObject.StartTime + CONTROL_POINT_LENIENCY + 1) ?? SampleControlPoint.DEFAULT;
|
||||
hitObject.Samples = hitObject.Samples.Select(o => sampleControlPoint.ApplyTo(o)).ToList();
|
||||
|
||||
for (int i = 0; i < hasRepeats.NodeSamples.Count; i++)
|
||||
{
|
||||
double time = hitObject.StartTime + i * hasRepeats.Duration / hasRepeats.SpanCount() + control_point_leniency;
|
||||
double time = hitObject.StartTime + i * hasRepeats.Duration / hasRepeats.SpanCount() + CONTROL_POINT_LENIENCY;
|
||||
var nodeSamplePoint = (beatmap.ControlPointInfo as LegacyControlPointInfo)?.SamplePointAt(time) ?? SampleControlPoint.DEFAULT;
|
||||
|
||||
hasRepeats.NodeSamples[i] = hasRepeats.NodeSamples[i].Select(o => nodeSamplePoint.ApplyTo(o)).ToList();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SampleControlPoint sampleControlPoint = (beatmap.ControlPointInfo as LegacyControlPointInfo)?.SamplePointAt(hitObject.GetEndTime() + CONTROL_POINT_LENIENCY) ?? SampleControlPoint.DEFAULT;
|
||||
hitObject.Samples = hitObject.Samples.Select(o => sampleControlPoint.ApplyTo(o)).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -282,19 +282,39 @@ namespace osu.Game.Beatmaps.Formats
|
||||
{
|
||||
foreach (var hitObject in hitObjects)
|
||||
{
|
||||
if (hitObject.Samples.Count > 0)
|
||||
if (hitObject is IHasRepeats hasNodeSamples)
|
||||
{
|
||||
int volume = hitObject.Samples.Max(o => o.Volume);
|
||||
int customIndex = hitObject.Samples.Any(o => o is ConvertHitObjectParser.LegacyHitSampleInfo)
|
||||
? hitObject.Samples.OfType<ConvertHitObjectParser.LegacyHitSampleInfo>().Max(o => o.CustomSampleBank)
|
||||
: -1;
|
||||
double spanDuration = hasNodeSamples.Duration / hasNodeSamples.SpanCount();
|
||||
|
||||
yield return new LegacyBeatmapDecoder.LegacySampleControlPoint { Time = hitObject.GetEndTime(), SampleVolume = volume, CustomSampleBank = customIndex };
|
||||
for (int i = 0; i < hasNodeSamples.NodeSamples.Count; ++i)
|
||||
{
|
||||
double nodeTime = hitObject.StartTime + i * spanDuration;
|
||||
|
||||
if (hasNodeSamples.NodeSamples[i].Count > 0)
|
||||
yield return createSampleControlPointFor(nodeTime, hasNodeSamples.NodeSamples[i]);
|
||||
|
||||
if (spanDuration > LegacyBeatmapDecoder.CONTROL_POINT_LENIENCY + 1 && hitObject.Samples.Count > 0 && i < hasNodeSamples.NodeSamples.Count - 1)
|
||||
yield return createSampleControlPointFor(nodeTime + LegacyBeatmapDecoder.CONTROL_POINT_LENIENCY + 1, hitObject.Samples);
|
||||
}
|
||||
}
|
||||
else if (hitObject.Samples.Count > 0)
|
||||
{
|
||||
yield return createSampleControlPointFor(hitObject.GetEndTime(), hitObject.Samples);
|
||||
}
|
||||
|
||||
foreach (var nested in collectSampleControlPoints(hitObject.NestedHitObjects))
|
||||
yield return nested;
|
||||
}
|
||||
|
||||
SampleControlPoint createSampleControlPointFor(double time, IList<HitSampleInfo> samples)
|
||||
{
|
||||
int volume = samples.Max(o => o.Volume);
|
||||
int customIndex = samples.Any(o => o is ConvertHitObjectParser.LegacyHitSampleInfo)
|
||||
? samples.OfType<ConvertHitObjectParser.LegacyHitSampleInfo>().Max(o => o.CustomSampleBank)
|
||||
: -1;
|
||||
|
||||
return new LegacyBeatmapDecoder.LegacySampleControlPoint { Time = time, SampleVolume = volume, CustomSampleBank = customIndex };
|
||||
}
|
||||
}
|
||||
|
||||
void extractSampleControlPoints(IEnumerable<HitObject> hitObject)
|
||||
|
Loading…
Reference in New Issue
Block a user