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

Merge pull request #30281 from bdach/remove-irrelevant-hacks

Fix slider ticks and repeats incorrectly moved to position of head when strict tracking and any conversion mod that moves objects is active
This commit is contained in:
Dan Balasescu 2024-10-17 14:10:36 +09:00 committed by GitHub
commit 80c77e6e05
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 71 additions and 14 deletions

View File

@ -0,0 +1,64 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. 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.Framework.Utils;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Beatmaps;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Osu.UI;
using osuTK;
namespace osu.Game.Rulesets.Osu.Tests.Mods
{
public partial class TestSceneOsuModMirror : OsuModTestScene
{
[Test]
public void TestCorrectReflections([Values] OsuModMirror.MirrorType type, [Values] bool withStrictTracking) => CreateModTest(new ModTestData
{
Autoplay = true,
Beatmap = new OsuBeatmap
{
HitObjects =
{
new Slider
{
Position = new Vector2(0),
Path = new SliderPath
{
ControlPoints =
{
new PathControlPoint(),
new PathControlPoint(new Vector2(100, 0))
}
},
TickDistanceMultiplier = 0.5,
RepeatCount = 1,
}
}
},
Mods = withStrictTracking
? [new OsuModMirror { Reflection = { Value = type } }, new OsuModStrictTracking()]
: [new OsuModMirror { Reflection = { Value = type } }],
PassCondition = () =>
{
var slider = this.ChildrenOfType<DrawableSlider>().SingleOrDefault();
var playfield = this.ChildrenOfType<OsuPlayfield>().Single();
if (slider == null)
return false;
return Precision.AlmostEquals(playfield.ToLocalSpace(slider.HeadCircle.ScreenSpaceDrawQuad.Centre), slider.HitObject.Position)
&& Precision.AlmostEquals(playfield.ToLocalSpace(slider.TailCircle.ScreenSpaceDrawQuad.Centre), slider.HitObject.Position)
&& Precision.AlmostEquals(playfield.ToLocalSpace(slider.NestedHitObjects.OfType<DrawableSliderRepeat>().Single().ScreenSpaceDrawQuad.Centre),
slider.HitObject.Position + slider.HitObject.Path.PositionAt(1))
&& Precision.AlmostEquals(playfield.ToLocalSpace(slider.NestedHitObjects.OfType<DrawableSliderTick>().First().ScreenSpaceDrawQuad.Centre),
slider.HitObject.Position + slider.HitObject.Path.PositionAt(0.7f));
}
});
}
}

View File

@ -120,6 +120,7 @@ namespace osu.Game.Rulesets.Osu.Mods
Position = Position + Path.PositionAt(e.PathProgress), Position = Position + Path.PositionAt(e.PathProgress),
StackHeight = StackHeight, StackHeight = StackHeight,
Scale = Scale, Scale = Scale,
PathProgress = e.PathProgress,
}); });
break; break;
@ -150,6 +151,7 @@ namespace osu.Game.Rulesets.Osu.Mods
Position = Position + Path.PositionAt(e.PathProgress), Position = Position + Path.PositionAt(e.PathProgress),
StackHeight = StackHeight, StackHeight = StackHeight,
Scale = Scale, Scale = Scale,
PathProgress = e.PathProgress,
}); });
break; break;
} }

View File

@ -3,7 +3,6 @@
using System; using System;
using System.Linq; using System.Linq;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.Osu.UI;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Rulesets.Osu.Beatmaps;
@ -117,10 +116,9 @@ namespace osu.Game.Rulesets.Osu.Utils
if (osuObject is not Slider slider) if (osuObject is not Slider slider)
return; return;
void reflectNestedObject(OsuHitObject nested) => nested.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - nested.Position.X, nested.Position.Y);
static void reflectControlPoint(PathControlPoint point) => point.Position = new Vector2(-point.Position.X, point.Position.Y); static void reflectControlPoint(PathControlPoint point) => point.Position = new Vector2(-point.Position.X, point.Position.Y);
modifySlider(slider, reflectNestedObject, reflectControlPoint); modifySlider(slider, reflectControlPoint);
} }
/// <summary> /// <summary>
@ -134,10 +132,9 @@ namespace osu.Game.Rulesets.Osu.Utils
if (osuObject is not Slider slider) if (osuObject is not Slider slider)
return; return;
void reflectNestedObject(OsuHitObject nested) => nested.Position = new Vector2(nested.Position.X, OsuPlayfield.BASE_SIZE.Y - nested.Position.Y);
static void reflectControlPoint(PathControlPoint point) => point.Position = new Vector2(point.Position.X, -point.Position.Y); static void reflectControlPoint(PathControlPoint point) => point.Position = new Vector2(point.Position.X, -point.Position.Y);
modifySlider(slider, reflectNestedObject, reflectControlPoint); modifySlider(slider, reflectControlPoint);
} }
/// <summary> /// <summary>
@ -146,10 +143,9 @@ namespace osu.Game.Rulesets.Osu.Utils
/// <param name="slider">The slider to be flipped.</param> /// <param name="slider">The slider to be flipped.</param>
public static void FlipSliderInPlaceHorizontally(Slider slider) public static void FlipSliderInPlaceHorizontally(Slider slider)
{ {
void flipNestedObject(OsuHitObject nested) => nested.Position = new Vector2(slider.X - (nested.X - slider.X), nested.Y);
static void flipControlPoint(PathControlPoint point) => point.Position = new Vector2(-point.Position.X, point.Position.Y); static void flipControlPoint(PathControlPoint point) => point.Position = new Vector2(-point.Position.X, point.Position.Y);
modifySlider(slider, flipNestedObject, flipControlPoint); modifySlider(slider, flipControlPoint);
} }
/// <summary> /// <summary>
@ -159,18 +155,13 @@ namespace osu.Game.Rulesets.Osu.Utils
/// <param name="rotation">The angle, measured in radians, to rotate the slider by.</param> /// <param name="rotation">The angle, measured in radians, to rotate the slider by.</param>
public static void RotateSlider(Slider slider, float rotation) public static void RotateSlider(Slider slider, float rotation)
{ {
void rotateNestedObject(OsuHitObject nested) => nested.Position = rotateVector(nested.Position - slider.Position, rotation) + slider.Position;
void rotateControlPoint(PathControlPoint point) => point.Position = rotateVector(point.Position, rotation); void rotateControlPoint(PathControlPoint point) => point.Position = rotateVector(point.Position, rotation);
modifySlider(slider, rotateNestedObject, rotateControlPoint); modifySlider(slider, rotateControlPoint);
} }
private static void modifySlider(Slider slider, Action<OsuHitObject> modifyNestedObject, Action<PathControlPoint> modifyControlPoint) private static void modifySlider(Slider slider, Action<PathControlPoint> modifyControlPoint)
{ {
// No need to update the head and tail circles, since slider handles that when the new slider path is set
slider.NestedHitObjects.OfType<SliderTick>().ForEach(modifyNestedObject);
slider.NestedHitObjects.OfType<SliderRepeat>().ForEach(modifyNestedObject);
var controlPoints = slider.Path.ControlPoints.Select(p => new PathControlPoint(p.Position, p.Type)).ToArray(); var controlPoints = slider.Path.ControlPoints.Select(p => new PathControlPoint(p.Position, p.Type)).ToArray();
foreach (var point in controlPoints) foreach (var point in controlPoints)
modifyControlPoint(point); modifyControlPoint(point);