From eab02a2aa54bedb6305d0c4b4d90ded243fe29e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 10 Jun 2025 14:04:56 +0200 Subject: [PATCH] Fix lack of slider encode-decode stability due to truncating control point coordinates Mostly closes https://github.com/ppy/osu/issues/33505. Compare https://github.com/ppy/osu/blob/97e6187f0d7c3dbee896596a623e34627135bf0e/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs#L56-L59 I say "mostly" here because I'm rather skeptical that this is 100% rock solid still, for one reason - namely that the game stores path control point coordinates relative to the head, then turns them into absolute coordinates when encoding, and then on decoding turns them back into coordinates relative to the head, which in floating-point world is a Bad Idea because of round-off error. But I'm not fixing that without introducing a completely new beatmap format or rewriting half the editor to address that, so I'll just pretend that I don't know any of this until someone notices. --- osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index 0162c8017b..c5a6c9e83d 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -335,11 +335,14 @@ namespace osu.Game.Rulesets.Objects.Legacy ArrayPool<(PathType, int)>.Shared.Return(segmentsBuffer); } - static Vector2 readPoint(string value, Vector2 startPos) + Vector2 readPoint(string value, Vector2 startPos) { string[] vertexSplit = value.Split(':'); - Vector2 pos = new Vector2((int)Parsing.ParseDouble(vertexSplit[0], Parsing.MAX_COORDINATE_VALUE), (int)Parsing.ParseDouble(vertexSplit[1], Parsing.MAX_COORDINATE_VALUE)) - startPos; + Vector2 pos = formatVersion >= LegacyBeatmapEncoder.FIRST_LAZER_VERSION + ? new Vector2(Parsing.ParseFloat(vertexSplit[0], Parsing.MAX_COORDINATE_VALUE), Parsing.ParseFloat(vertexSplit[1], Parsing.MAX_COORDINATE_VALUE)) + : new Vector2((int)Parsing.ParseFloat(vertexSplit[0], Parsing.MAX_COORDINATE_VALUE), (int)Parsing.ParseFloat(vertexSplit[1], Parsing.MAX_COORDINATE_VALUE)); + pos -= startPos; return pos; } }