1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-25 03:49:55 +08:00

Move control point double-up logic to LegacyBeatmapExporter

Done for two reasons:

- During review it was requested for the logic to be moved out of
  `BezierConverter` as `BezierConverter` was intended to produce
  "lazer style" sliders with per-control-point curve types,
  as a future usability / code layering concern.

- It is also relevant for encode-decode stability. With how the logic
  was structured between the Bezier converter and the legacy beatmap
  encoder, the encoder would leave behind per-control-point Bezier curve
  specs that stable ignored, but subsequent encodes and decodes in lazer
  would end up multiplying the doubled-up control points ad nauseam.
  Instead, it is sufficient to only specify the curve type for the
  head control point as Bezier, not specify any further curve types
  later on, and instead just keep the double-up-control-point for new
  implicit segment logic which is enough to make stable cooperate
  (and also as close to outputting the slider exactly as stable would
  have produced it as we've ever been)
This commit is contained in:
Bartłomiej Dach
2025-01-30 15:23:22 +01:00
Unverified
parent 749704344c
commit b4f63da048
2 changed files with 22 additions and 14 deletions
+22 -10
View File
@@ -120,18 +120,30 @@ namespace osu.Game.Database
if (BezierConverter.CountSegments(hasPath.Path.ControlPoints) <= 1
&& hasPath.Path.ControlPoints[0].Type!.Value.Degree == null) continue;
var newControlPoints = BezierConverter.ConvertToModernBezier(hasPath.Path.ControlPoints);
// Truncate control points to integer positions
foreach (var pathControlPoint in newControlPoints)
{
pathControlPoint.Position = new Vector2(
(float)Math.Floor(pathControlPoint.Position.X),
(float)Math.Floor(pathControlPoint.Position.Y));
}
var convertedToBezier = BezierConverter.ConvertToModernBezier(hasPath.Path.ControlPoints);
hasPath.Path.ControlPoints.Clear();
hasPath.Path.ControlPoints.AddRange(newControlPoints);
for (int i = 0; i < convertedToBezier.Count; i++)
{
var convertedPoint = convertedToBezier[i];
// Truncate control points to integer positions
var position = new Vector2(
(float)Math.Floor(convertedPoint.Position.X),
(float)Math.Floor(convertedPoint.Position.Y));
// stable only supports a single curve type specification per slider.
// we exploit the fact that the converted-to-Bézier path only has Bézier segments,
// and thus we specify the Bézier curve type once ever at the start of the slider.
hasPath.Path.ControlPoints.Add(new PathControlPoint(position, i == 0 ? PathType.BEZIER : null));
// however, the Bézier path as output by the converter has multiple segments.
// `LegacyBeatmapEncoder` will attempt to encode this by emitting per-control-point curve type specs which don't do anything for stable.
// instead, stable expects control points that start a segment to be present in the path twice in succession.
if (convertedPoint.Type == PathType.BEZIER)
hasPath.Path.ControlPoints.Add(new PathControlPoint(position));
}
}
// Encode to legacy format
@@ -136,7 +136,6 @@ namespace osu.Game.Rulesets.Objects
{
for (int j = 0; j < segment.Length - 1; j++)
{
if (result.Count > 0 && j == 0) result.Add(new PathControlPoint(segment[j]));
result.Add(new PathControlPoint(segment[j], j == 0 ? PathType.BEZIER : null));
}
}
@@ -148,7 +147,6 @@ namespace osu.Game.Rulesets.Objects
{
for (int j = 0; j < segment.Length - 1; j++)
{
if (result.Count > 0 && j == 0) result.Add(new PathControlPoint(segment[j]));
result.Add(new PathControlPoint(segment[j], j == 0 ? PathType.BEZIER : null));
}
}
@@ -160,7 +158,6 @@ namespace osu.Game.Rulesets.Objects
for (int j = 0; j < circleResult.Length - 1; j++)
{
if (result.Count > 0 && j == 0) result.Add(new PathControlPoint(circleResult[j]));
result.Add(new PathControlPoint(circleResult[j], j == 0 ? PathType.BEZIER : null));
}
@@ -173,7 +170,6 @@ namespace osu.Game.Rulesets.Objects
for (int j = 0; j < bSplineResult.Length - 1; j++)
{
if (result.Count > 0 && j == 0) result.Add(new PathControlPoint(bSplineResult[j]));
result.Add(new PathControlPoint(bSplineResult[j], j == 0 ? PathType.BEZIER : null));
}