mirror of
https://github.com/ppy/osu.git
synced 2025-01-26 12:25:04 +08:00
Merge pull request #16420 from bdach/slider-paste-parsing-failures-2
Fix pasted sliders having sample points with time at infinity
This commit is contained in:
commit
eb5f15a77e
@ -4,6 +4,7 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
@ -85,11 +86,17 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
|
|
||||||
AddAssert("is one object", () => EditorBeatmap.HitObjects.Count == 1);
|
AddAssert("is one object", () => EditorBeatmap.HitObjects.Count == 1);
|
||||||
|
|
||||||
|
Slider slider = null;
|
||||||
|
AddStep("retrieve slider", () => slider = (Slider)EditorBeatmap.HitObjects.Single());
|
||||||
AddAssert("path matches", () =>
|
AddAssert("path matches", () =>
|
||||||
{
|
{
|
||||||
var path = ((Slider)EditorBeatmap.HitObjects.Single()).Path;
|
var path = slider.Path;
|
||||||
return path.ControlPoints.Count == 2 && path.ControlPoints.SequenceEqual(addedObject.Path.ControlPoints);
|
return path.ControlPoints.Count == 2 && path.ControlPoints.SequenceEqual(addedObject.Path.ControlPoints);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// see `HitObject.control_point_leniency`.
|
||||||
|
AddAssert("sample control point has correct time", () => Precision.AlmostEquals(slider.SampleControlPoint.Time, slider.GetEndTime(), 1));
|
||||||
|
AddAssert("difficulty control point has correct time", () => slider.DifficultyControlPoint.Time == slider.StartTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -87,23 +87,6 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public SlimReadOnlyListWrapper<HitObject> NestedHitObjects => nestedHitObjects.AsSlimReadOnly();
|
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>
|
/// <summary>
|
||||||
/// Applies default values to this HitObject.
|
/// Applies default values to this HitObject.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -115,24 +98,22 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
var legacyInfo = controlPointInfo as LegacyControlPointInfo;
|
var legacyInfo = controlPointInfo as LegacyControlPointInfo;
|
||||||
|
|
||||||
if (legacyInfo != null)
|
if (legacyInfo != null)
|
||||||
{
|
|
||||||
DifficultyControlPoint = (DifficultyControlPoint)legacyInfo.DifficultyPointAt(StartTime).DeepClone();
|
DifficultyControlPoint = (DifficultyControlPoint)legacyInfo.DifficultyPointAt(StartTime).DeepClone();
|
||||||
DifficultyControlPoint.Time = StartTime;
|
|
||||||
}
|
|
||||||
else if (DifficultyControlPoint == DifficultyControlPoint.DEFAULT)
|
else if (DifficultyControlPoint == DifficultyControlPoint.DEFAULT)
|
||||||
DifficultyControlPoint = new DifficultyControlPoint();
|
DifficultyControlPoint = new DifficultyControlPoint();
|
||||||
|
|
||||||
|
DifficultyControlPoint.Time = StartTime;
|
||||||
|
|
||||||
ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
||||||
|
|
||||||
// This is done here after ApplyDefaultsToSelf as we may require custom defaults to be applied to have an accurate end time.
|
// This is done here after ApplyDefaultsToSelf as we may require custom defaults to be applied to have an accurate end time.
|
||||||
if (legacyInfo != null)
|
if (legacyInfo != null)
|
||||||
{
|
|
||||||
SampleControlPoint = (SampleControlPoint)legacyInfo.SamplePointAt(this.GetEndTime() + control_point_leniency).DeepClone();
|
SampleControlPoint = (SampleControlPoint)legacyInfo.SamplePointAt(this.GetEndTime() + control_point_leniency).DeepClone();
|
||||||
SampleControlPoint.Time = this.GetEndTime() + control_point_leniency;
|
|
||||||
}
|
|
||||||
else if (SampleControlPoint == SampleControlPoint.DEFAULT)
|
else if (SampleControlPoint == SampleControlPoint.DEFAULT)
|
||||||
SampleControlPoint = new SampleControlPoint();
|
SampleControlPoint = new SampleControlPoint();
|
||||||
|
|
||||||
|
SampleControlPoint.Time = this.GetEndTime() + control_point_leniency;
|
||||||
|
|
||||||
nestedHitObjects.Clear();
|
nestedHitObjects.Clear();
|
||||||
|
|
||||||
CreateNestedHitObjects(cancellationToken);
|
CreateNestedHitObjects(cancellationToken);
|
||||||
@ -155,7 +136,28 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
foreach (var h in nestedHitObjects)
|
foreach (var h in nestedHitObjects)
|
||||||
h.ApplyDefaults(controlPointInfo, difficulty, cancellationToken);
|
h.ApplyDefaults(controlPointInfo, difficulty, cancellationToken);
|
||||||
|
|
||||||
|
// `ApplyDefaults()` may be called multiple times on a single hitobject.
|
||||||
|
// to prevent subscribing to `StartTimeBindable.ValueChanged` multiple times with the same callback,
|
||||||
|
// remove the previous subscription (if present) before (re-)registering.
|
||||||
|
StartTimeBindable.ValueChanged -= onStartTimeChanged;
|
||||||
|
|
||||||
|
// this callback must be (re-)registered after default application
|
||||||
|
// to ensure that the read of `this.GetEndTime()` within `onStartTimeChanged` doesn't return an invalid value
|
||||||
|
// if `StartTimeBindable` is changed prior to default application.
|
||||||
|
StartTimeBindable.ValueChanged += onStartTimeChanged;
|
||||||
|
|
||||||
DefaultsApplied?.Invoke(this);
|
DefaultsApplied?.Invoke(this);
|
||||||
|
|
||||||
|
void onStartTimeChanged(ValueChangedEvent<double> time)
|
||||||
|
{
|
||||||
|
double offset = time.NewValue - time.OldValue;
|
||||||
|
|
||||||
|
foreach (var nested in nestedHitObjects)
|
||||||
|
nested.StartTime += offset;
|
||||||
|
|
||||||
|
DifficultyControlPoint.Time = time.NewValue;
|
||||||
|
SampleControlPoint.Time = this.GetEndTime() + control_point_leniency;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, IBeatmapDifficultyInfo difficulty)
|
protected virtual void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, IBeatmapDifficultyInfo difficulty)
|
||||||
|
Loading…
Reference in New Issue
Block a user