mirror of
https://github.com/ppy/osu.git
synced 2025-02-20 18:43:04 +08:00
Merge pull request #31305 from bdach/round-coordinates-on-legacy-export
Round object coordinates to nearest integers on legacy export rather than truncating
This commit is contained in:
commit
9da27b5fe5
@ -14,7 +14,16 @@ namespace osu.Game.Rulesets.EmptyFreeform.Objects
|
||||
|
||||
public Vector2 Position { get; set; }
|
||||
|
||||
public float X => Position.X;
|
||||
public float Y => Position.Y;
|
||||
public float X
|
||||
{
|
||||
get => Position.X;
|
||||
set => Position = new Vector2(value, Y);
|
||||
}
|
||||
|
||||
public float Y
|
||||
{
|
||||
get => Position.Y;
|
||||
set => Position = new Vector2(X, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,16 @@ namespace osu.Game.Rulesets.Pippidon.Objects
|
||||
|
||||
public Vector2 Position { get; set; }
|
||||
|
||||
public float X => Position.X;
|
||||
public float Y => Position.Y;
|
||||
public float X
|
||||
{
|
||||
get => Position.X;
|
||||
set => Position = new Vector2(value, Y);
|
||||
}
|
||||
|
||||
public float Y
|
||||
{
|
||||
get => Position.Y;
|
||||
set => Position = new Vector2(X, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -210,11 +210,27 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
/// </summary>
|
||||
public float LegacyConvertedY { get; set; } = DEFAULT_LEGACY_CONVERT_Y;
|
||||
|
||||
float IHasXPosition.X => OriginalX;
|
||||
float IHasXPosition.X
|
||||
{
|
||||
get => OriginalX;
|
||||
set => OriginalX = value;
|
||||
}
|
||||
|
||||
float IHasYPosition.Y => LegacyConvertedY;
|
||||
float IHasYPosition.Y
|
||||
{
|
||||
get => LegacyConvertedY;
|
||||
set => LegacyConvertedY = value;
|
||||
}
|
||||
|
||||
Vector2 IHasPosition.Position => new Vector2(OriginalX, LegacyConvertedY);
|
||||
Vector2 IHasPosition.Position
|
||||
{
|
||||
get => new Vector2(OriginalX, LegacyConvertedY);
|
||||
set
|
||||
{
|
||||
((IHasXPosition)this).X = value.X;
|
||||
((IHasYPosition)this).Y = value.Y;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
@ -25,7 +25,11 @@ namespace osu.Game.Rulesets.Mania.Objects
|
||||
|
||||
#region LegacyBeatmapEncoder
|
||||
|
||||
float IHasXPosition.X => Column;
|
||||
float IHasXPosition.X
|
||||
{
|
||||
get => Column;
|
||||
set => Column = (int)value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
@ -59,8 +59,17 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
set => position.Value = value;
|
||||
}
|
||||
|
||||
public float X => Position.X;
|
||||
public float Y => Position.Y;
|
||||
public float X
|
||||
{
|
||||
get => Position.X;
|
||||
set => Position = new Vector2(value, Position.Y);
|
||||
}
|
||||
|
||||
public float Y
|
||||
{
|
||||
get => Position.Y;
|
||||
set => Position = new Vector2(Position.X, value);
|
||||
}
|
||||
|
||||
public Vector2 StackedPosition => Position + StackOffset;
|
||||
|
||||
|
@ -11,6 +11,7 @@ using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.IO.Archives;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Tests.Resources;
|
||||
using osu.Game.Tests.Visual;
|
||||
using MemoryStream = System.IO.MemoryStream;
|
||||
@ -50,6 +51,29 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
AddAssert("hit object is snapped", () => beatmap.Beatmap.HitObjects[0].StartTime, () => Is.EqualTo(28519).Within(0.001));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFractionalObjectCoordinatesRounded()
|
||||
{
|
||||
IWorkingBeatmap beatmap = null!;
|
||||
MemoryStream outStream = null!;
|
||||
|
||||
// Ensure importer encoding is correct
|
||||
AddStep("import beatmap", () => beatmap = importBeatmapFromArchives(@"fractional-coordinates.olz"));
|
||||
AddAssert("hit object has fractional position", () => ((IHasYPosition)beatmap.Beatmap.HitObjects[1]).Y, () => Is.EqualTo(383.99997).Within(0.00001));
|
||||
|
||||
// Ensure exporter legacy conversion is correct
|
||||
AddStep("export", () =>
|
||||
{
|
||||
outStream = new MemoryStream();
|
||||
|
||||
new LegacyBeatmapExporter(LocalStorage)
|
||||
.ExportToStream((BeatmapSetInfo)beatmap.BeatmapInfo.BeatmapSet!, outStream, null);
|
||||
});
|
||||
|
||||
AddStep("import beatmap again", () => beatmap = importBeatmapFromStream(outStream));
|
||||
AddAssert("hit object is snapped", () => ((IHasYPosition)beatmap.Beatmap.HitObjects[1]).Y, () => Is.EqualTo(384).Within(0.00001));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestExportStability()
|
||||
{
|
||||
|
BIN
osu.Game.Tests/Resources/Archives/fractional-coordinates.olz
Normal file
BIN
osu.Game.Tests/Resources/Archives/fractional-coordinates.olz
Normal file
Binary file not shown.
@ -42,7 +42,10 @@ namespace osu.Game.Database
|
||||
return null;
|
||||
|
||||
using var contentStreamReader = new LineBufferedReader(contentStream);
|
||||
var beatmapContent = new LegacyBeatmapDecoder().Decode(contentStreamReader);
|
||||
|
||||
// FIRST_LAZER_VERSION is specified here to avoid flooring object coordinates on decode via `(int)` casts.
|
||||
// we will be making integers out of them lower down, but in a slightly different manner (rounding rather than truncating)
|
||||
var beatmapContent = new LegacyBeatmapDecoder(LegacyBeatmapEncoder.FIRST_LAZER_VERSION).Decode(contentStreamReader);
|
||||
|
||||
var workingBeatmap = new FlatWorkingBeatmap(beatmapContent);
|
||||
var playableBeatmap = workingBeatmap.GetPlayableBeatmap(beatmapInfo.Ruleset);
|
||||
@ -93,6 +96,12 @@ namespace osu.Game.Database
|
||||
|
||||
hitObject.StartTime = Math.Floor(hitObject.StartTime);
|
||||
|
||||
if (hitObject is IHasXPosition hasXPosition)
|
||||
hasXPosition.X = MathF.Round(hasXPosition.X);
|
||||
|
||||
if (hitObject is IHasYPosition hasYPosition)
|
||||
hasYPosition.Y = MathF.Round(hasYPosition.Y);
|
||||
|
||||
if (hitObject is not IHasPath hasPath) continue;
|
||||
|
||||
// stable's hit object parsing expects the entire slider to use only one type of curve,
|
||||
|
@ -21,9 +21,17 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
||||
|
||||
public int ComboOffset { get; set; }
|
||||
|
||||
public float X => Position.X;
|
||||
public float X
|
||||
{
|
||||
get => Position.X;
|
||||
set => Position = new Vector2(value, Position.Y);
|
||||
}
|
||||
|
||||
public float Y => Position.Y;
|
||||
public float Y
|
||||
{
|
||||
get => Position.Y;
|
||||
set => Position = new Vector2(Position.X, value);
|
||||
}
|
||||
|
||||
public Vector2 Position { get; set; }
|
||||
|
||||
|
@ -13,6 +13,6 @@ namespace osu.Game.Rulesets.Objects.Types
|
||||
/// <summary>
|
||||
/// The starting position of the HitObject.
|
||||
/// </summary>
|
||||
Vector2 Position { get; }
|
||||
Vector2 Position { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,6 @@ namespace osu.Game.Rulesets.Objects.Types
|
||||
/// <summary>
|
||||
/// The starting X-position of this HitObject.
|
||||
/// </summary>
|
||||
float X { get; }
|
||||
float X { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,6 @@ namespace osu.Game.Rulesets.Objects.Types
|
||||
/// <summary>
|
||||
/// The starting Y-position of this HitObject.
|
||||
/// </summary>
|
||||
float Y { get; }
|
||||
float Y { get; set; }
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user