diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs
index bb3fe7db06..e49d72ef33 100644
--- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs
+++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs
@@ -15,7 +15,11 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
{
public class OsuBeatmapProcessor : BeatmapProcessor
{
- private const int stack_distance = 3;
+ ///
+ /// The maximum distance between the end of one object and the start of another
+ /// which allows the objects to be stacked on top of another.
+ ///
+ public const int STACK_DISTANCE = 3;
public OsuBeatmapProcessor(IBeatmap beatmap)
: base(beatmap)
@@ -93,8 +97,8 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
// We are no longer within stacking range of the next object.
break;
- if (Vector2Extensions.Distance(stackBaseObject.Position, objectN.Position) < stack_distance
- || (stackBaseObject is Slider && Vector2Extensions.Distance(stackBaseObject.EndPosition, objectN.Position) < stack_distance))
+ if (Vector2Extensions.Distance(stackBaseObject.Position, objectN.Position) < STACK_DISTANCE
+ || (stackBaseObject is Slider && Vector2Extensions.Distance(stackBaseObject.EndPosition, objectN.Position) < STACK_DISTANCE))
{
stackBaseIndex = n;
@@ -163,7 +167,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
* o <- hitCircle has stack of -1
* o <- hitCircle has stack of -2
*/
- if (objectN is Slider && Vector2Extensions.Distance(objectN.EndPosition, objectI.Position) < stack_distance)
+ if (objectN is Slider && Vector2Extensions.Distance(objectN.EndPosition, objectI.Position) < STACK_DISTANCE)
{
int offset = objectI.StackHeight - objectN.StackHeight + 1;
@@ -171,7 +175,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
{
// For each object which was declared under this slider, we will offset it to appear *below* the slider end (rather than above).
OsuHitObject objectJ = hitObjects[j];
- if (Vector2Extensions.Distance(objectN.EndPosition, objectJ.Position) < stack_distance)
+ if (Vector2Extensions.Distance(objectN.EndPosition, objectJ.Position) < STACK_DISTANCE)
objectJ.StackHeight -= offset;
}
@@ -180,7 +184,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
break;
}
- if (Vector2Extensions.Distance(objectN.Position, objectI.Position) < stack_distance)
+ if (Vector2Extensions.Distance(objectN.Position, objectI.Position) < STACK_DISTANCE)
{
// Keep processing as if there are no sliders. If we come across a slider, this gets cancelled out.
//NOTE: Sliders with start positions stacking are a special case that is also handled here.
@@ -204,7 +208,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
// We are no longer within stacking range of the previous object.
break;
- if (Vector2Extensions.Distance(objectN.EndPosition, objectI.Position) < stack_distance)
+ if (Vector2Extensions.Distance(objectN.EndPosition, objectI.Position) < STACK_DISTANCE)
{
objectN.StackHeight = objectI.StackHeight + 1;
objectI = objectN;
@@ -245,12 +249,12 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
// Effects of this can be seen on https://osu.ppy.sh/beatmapsets/243#osu/1146 at sliders around 86647 ms, where
// if we use `EndTime` here it would result in unexpected stacking.
- if (Vector2Extensions.Distance(hitObjects[j].Position, currHitObject.Position) < stack_distance)
+ if (Vector2Extensions.Distance(hitObjects[j].Position, currHitObject.Position) < STACK_DISTANCE)
{
currHitObject.StackHeight++;
startTime = hitObjects[j].StartTime;
}
- else if (Vector2Extensions.Distance(hitObjects[j].Position, position2) < stack_distance)
+ else if (Vector2Extensions.Distance(hitObjects[j].Position, position2) < STACK_DISTANCE)
{
// Case for sliders - bump notes down and right, rather than up and left.
sliderStack++;
diff --git a/osu.Game.Rulesets.Osu/Edit/OsuDistanceSnapProvider.cs b/osu.Game.Rulesets.Osu/Edit/OsuDistanceSnapProvider.cs
index 45ce3206d2..6be60e4554 100644
--- a/osu.Game.Rulesets.Osu/Edit/OsuDistanceSnapProvider.cs
+++ b/osu.Game.Rulesets.Osu/Edit/OsuDistanceSnapProvider.cs
@@ -7,6 +7,7 @@ using osu.Game.Input.Bindings;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
+using osu.Game.Rulesets.Osu.Beatmaps;
using osu.Game.Rulesets.Osu.Objects;
using osuTK;
@@ -16,10 +17,15 @@ namespace osu.Game.Rulesets.Osu.Edit
{
public override double ReadCurrentDistanceSnap(HitObject before, HitObject after)
{
+ // If the pair of hit objects in question here could feasibly be on the same stack, do not provide a distance snap value -
+ // they're likely too close to one another for the distance snap value to be useful anyway even if they somehow are not.
+ if (Vector2.Distance(((OsuHitObject)before).EndPosition, ((OsuHitObject)after).Position) < OsuBeatmapProcessor.STACK_DISTANCE)
+ return 0;
+
var lastObjectWithVelocity = EditorBeatmap.HitObjects.TakeWhile(ho => ho != after).OfType().LastOrDefault();
float expectedDistance = DurationToDistance(after.StartTime - before.GetEndTime(), before.StartTime, lastObjectWithVelocity);
- float actualDistance = Vector2.Distance(((OsuHitObject)before).EndPosition, ((OsuHitObject)after).Position);
+ float actualDistance = Vector2.Distance(((OsuHitObject)before).StackedEndPosition, ((OsuHitObject)after).StackedPosition);
return actualDistance / expectedDistance;
}