From ab1a1a1df4da3504a215b4acd22e39e88dca3b60 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 16 Apr 2021 16:55:17 +0900 Subject: [PATCH 1/2] Add failing test case due to div by zero --- .../Editor/TestSliderScaling.cs | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 osu.Game.Rulesets.Osu.Tests/Editor/TestSliderScaling.cs diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSliderScaling.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSliderScaling.cs new file mode 100644 index 0000000000..e29a67c770 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSliderScaling.cs @@ -0,0 +1,72 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Testing; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.UI; +using osu.Game.Screens.Edit.Compose.Components; +using osu.Game.Tests.Beatmaps; +using osuTK; +using osuTK.Input; + +namespace osu.Game.Rulesets.Osu.Tests.Editor +{ + [TestFixture] + public class TestSliderScaling : TestSceneOsuEditor + { + private OsuPlayfield playfield; + + protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(Ruleset.Value, false); + + public override void SetUpSteps() + { + base.SetUpSteps(); + AddStep("get playfield", () => playfield = Editor.ChildrenOfType().First()); + AddStep("seek to first timing point", () => EditorClock.Seek(Beatmap.Value.Beatmap.ControlPointInfo.TimingPoints.First().Time)); + } + + [Test] + public void TestScalingLinearSlider() + { + Slider slider = null; + + AddStep("Add slider", () => + { + slider = new Slider { StartTime = EditorClock.CurrentTime, Position = new Vector2(300) }; + + PathControlPoint[] points = + { + new PathControlPoint(new Vector2(0), PathType.Linear), + new PathControlPoint(new Vector2(100, 0)), + }; + + slider.Path = new SliderPath(points); + EditorBeatmap.Add(slider); + }); + + AddAssert("ensure object placed", () => EditorBeatmap.HitObjects.Count == 1); + + moveMouse(new Vector2(300)); + AddStep("select slider", () => InputManager.Click(MouseButton.Left)); + + double distanceBefore = 0; + + AddStep("store distance", () => distanceBefore = slider.Path.Distance); + + AddStep("move mouse to handle", () => InputManager.MoveMouseTo(Editor.ChildrenOfType().Skip(1).First())); + AddStep("begin drag", () => InputManager.PressButton(MouseButton.Left)); + moveMouse(new Vector2(300, 300)); + AddStep("end drag", () => InputManager.ReleaseButton(MouseButton.Left)); + + AddAssert("slider length shrunk", () => slider.Path.Distance < distanceBefore); + } + + private void moveMouse(Vector2 pos) => + AddStep($"move mouse to {pos}", () => InputManager.MoveMouseTo(playfield.ToScreenSpace(pos))); + } +} From 8de68e0ebf11ba4c39438e4c7ff051ff53bfbb53 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 16 Apr 2021 16:55:24 +0900 Subject: [PATCH 2/2] Fix div-by-zero when scaling a 1-dimensional slider --- osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs index 5a84bd6163..047634a3ab 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs @@ -205,10 +205,12 @@ namespace osu.Game.Rulesets.Osu.Edit Quad sliderQuad = getSurroundingQuad(slider.Path.ControlPoints.Select(p => p.Position.Value)); - // Limit minimum distance between control points after scaling to almost 0. Less than 0 causes the slider to flip, exactly 0 causes a crash through division by 0. + // Limit minimum distance between control points after scaling to almost 0. Less than 0 causes the slider to flip, exactly 0 causes a crash through division by 0. scale = Vector2.ComponentMax(new Vector2(Precision.FLOAT_EPSILON), sliderQuad.Size + scale) - sliderQuad.Size; - Vector2 pathRelativeDeltaScale = new Vector2(1 + scale.X / sliderQuad.Width, 1 + scale.Y / sliderQuad.Height); + Vector2 pathRelativeDeltaScale = new Vector2( + sliderQuad.Width == 0 ? 0 : 1 + scale.X / sliderQuad.Width, + sliderQuad.Height == 0 ? 0 : 1 + scale.Y / sliderQuad.Height); Queue oldControlPoints = new Queue();