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; }