1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 10:12:54 +08:00

Fix sample control point time being calculated before defaults applied

In editor contexts, the `StartTimeBindable` subscription in `HitObject`
was firing before defaults were applied, which in the case of sliders
manifested in an infinite end time. `ApplyDefaults()` also did not
always set the time of the control point to the correct value, which
matters when the beatmap is encoded.

Ensure that the control points receive the correct time values during
default application, and only register the `StartTimeBindable` change
callback after defaults have been successfully applied.
This commit is contained in:
Bartłomiej Dach 2022-01-11 21:27:22 +01:00
parent e91d3dd8b4
commit 7a25fe79b7
No known key found for this signature in database
GPG Key ID: BCECCD4FA41F6497

View File

@ -87,23 +87,6 @@ namespace osu.Game.Rulesets.Objects
[JsonIgnore]
public SlimReadOnlyListWrapper<HitObject> NestedHitObjects => nestedHitObjects.AsSlimReadOnly();
public HitObject()
{
StartTimeBindable.ValueChanged += time =>
{
double offset = time.NewValue - time.OldValue;
foreach (var nested in nestedHitObjects)
nested.StartTime += offset;
if (DifficultyControlPoint != DifficultyControlPoint.DEFAULT)
DifficultyControlPoint.Time = time.NewValue;
if (SampleControlPoint != SampleControlPoint.DEFAULT)
SampleControlPoint.Time = this.GetEndTime() + control_point_leniency;
};
}
/// <summary>
/// Applies default values to this HitObject.
/// </summary>
@ -115,24 +98,22 @@ namespace osu.Game.Rulesets.Objects
var legacyInfo = controlPointInfo as LegacyControlPointInfo;
if (legacyInfo != null)
{
DifficultyControlPoint = (DifficultyControlPoint)legacyInfo.DifficultyPointAt(StartTime).DeepClone();
DifficultyControlPoint.Time = StartTime;
}
else if (DifficultyControlPoint == DifficultyControlPoint.DEFAULT)
DifficultyControlPoint = new DifficultyControlPoint();
DifficultyControlPoint.Time = StartTime;
ApplyDefaultsToSelf(controlPointInfo, difficulty);
// This is done here after ApplyDefaultsToSelf as we may require custom defaults to be applied to have an accurate end time.
if (legacyInfo != null)
{
SampleControlPoint = (SampleControlPoint)legacyInfo.SamplePointAt(this.GetEndTime() + control_point_leniency).DeepClone();
SampleControlPoint.Time = this.GetEndTime() + control_point_leniency;
}
else if (SampleControlPoint == SampleControlPoint.DEFAULT)
SampleControlPoint = new SampleControlPoint();
SampleControlPoint.Time = this.GetEndTime() + control_point_leniency;
nestedHitObjects.Clear();
CreateNestedHitObjects(cancellationToken);
@ -155,6 +136,23 @@ namespace osu.Game.Rulesets.Objects
foreach (var h in nestedHitObjects)
h.ApplyDefaults(controlPointInfo, difficulty, cancellationToken);
// importantly, this callback is only registered after default application
// to ensure that the read of `this.GetEndTime()` within doesn't return an invalid value
// if `StartTimeBindable` is changed prior to default application.
StartTimeBindable.ValueChanged += time =>
{
double offset = time.NewValue - time.OldValue;
foreach (var nested in nestedHitObjects)
nested.StartTime += offset;
if (DifficultyControlPoint != DifficultyControlPoint.DEFAULT)
DifficultyControlPoint.Time = time.NewValue;
if (SampleControlPoint != SampleControlPoint.DEFAULT)
SampleControlPoint.Time = this.GetEndTime() + control_point_leniency;
};
DefaultsApplied?.Invoke(this);
}