Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,25 @@ public void TestOnlyEightComboColoursEncoded()
Assert.That(decodedAfterEncode.skin.Configuration.CustomComboColours, Has.Count.EqualTo(8));
}

[Test]
public void TestBackgroundOffsetsRoundTrip()
{
var beatmap = new Beatmap();
var meta = beatmap.BeatmapInfo.Metadata;
meta.BackgroundFile = "test bg.jpg";
meta.BackgroundOffsetX = 10.25f;
meta.BackgroundOffsetY = -42f;

var encoded = EncodeToLegacy((beatmap, new TestLegacySkin(beatmaps_resource_store, string.Empty)));
encoded.Position = 0;

var decoded = new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(new LineBufferedReader(encoded));

Assert.That(decoded.BeatmapInfo.Metadata.BackgroundFile, Is.EqualTo(meta.BackgroundFile));
Assert.That(decoded.BeatmapInfo.Metadata.BackgroundOffsetX, Is.EqualTo(meta.BackgroundOffsetX));
Assert.That(decoded.BeatmapInfo.Metadata.BackgroundOffsetY, Is.EqualTo(meta.BackgroundOffsetY));
}

[Test]
public void TestEncodeStabilityOfSliderWithFractionalCoordinates()
{
Expand Down
2 changes: 2 additions & 0 deletions osu.Game/Beatmaps/BeatmapImporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,8 @@ private List<BeatmapInfo> createBeatmapDifficulties(BeatmapSetInfo beatmapSet, R
PreviewTime = decoded.Metadata.PreviewTime,
AudioFile = decoded.Metadata.AudioFile,
BackgroundFile = decoded.Metadata.BackgroundFile,
BackgroundOffsetX = decoded.Metadata.BackgroundOffsetX,
BackgroundOffsetY = decoded.Metadata.BackgroundOffsetY,
};

var beatmap = new BeatmapInfo(ruleset, difficulty, metadata)
Expand Down
14 changes: 13 additions & 1 deletion osu.Game/Beatmaps/BeatmapMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@ public class BeatmapMetadata : RealmObject, IBeatmapMetadataInfo, IDeepCloneable
public string AudioFile { get; set; } = string.Empty;
public string BackgroundFile { get; set; } = string.Empty;

/// <summary>
/// Horizontal offset in pixels of the legacy Background event (fourth column in <c>[Events]</c>).
/// </summary>
public float BackgroundOffsetX { get; set; }

/// <summary>
/// Vertical offset in pixels of the legacy Background event (fifth column in <c>[Events]</c>).
/// </summary>
public float BackgroundOffsetY { get; set; }
Comment on lines +64 to +72
Copy link
Copy Markdown
Collaborator

@bdach bdach Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has no business being in BeatmapMetadata, or making its way into realm, or anything of the sort. The proper place for this is either Storyboard (ideal) or maybe Beatmap (less ideal).

Now, it's not trivial to put it there, and I don't have a concrete plan on how to do this, but it is going to be required anyways eventually, to support things like video adding, or eventually-eventually design mode support in editor. There likely need to be some hammers put to LegacyBeatmapDecoder and/or LegacyBeatmapEncoder because the way both entirely attempt to ignore the storyboard as hard as possible is going to stop working at some future point.

Something I'd likely need to try to have a go at myself. But I'm personally not okay with letting this into master only to need to migrate it out in a year.


public BeatmapMetadata(RealmUser? user = null)
{
Author = user ?? new RealmUser();
Expand All @@ -85,7 +95,9 @@ private BeatmapMetadata()
Tags = Tags,
PreviewTime = PreviewTime,
AudioFile = AudioFile,
BackgroundFile = BackgroundFile
BackgroundFile = BackgroundFile,
BackgroundOffsetX = BackgroundOffsetX,
BackgroundOffsetY = BackgroundOffsetY
};
}
}
9 changes: 8 additions & 1 deletion osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -465,9 +465,16 @@ private void handleEvent(string line)
break;

case LegacyEventType.Background:
beatmap.BeatmapInfo.Metadata.BackgroundFile = CleanFilename(split[2]);
{
var metadata = beatmap.BeatmapInfo.Metadata;
metadata.BackgroundFile = CleanFilename(split[2]);
if (split.Length > 3)
metadata.BackgroundOffsetX = Parsing.ParseFloat(split[3], Parsing.MAX_COORDINATE_VALUE);
if (split.Length > 4)
metadata.BackgroundOffsetY = Parsing.ParseFloat(split[4], Parsing.MAX_COORDINATE_VALUE);
lineSupportedByEncoder = true;
break;
}

case LegacyEventType.Break:
double start = getOffsetTime(Parsing.ParseDouble(split[1]));
Expand Down
5 changes: 4 additions & 1 deletion osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,10 @@ private void handleEvents(TextWriter writer)
writer.WriteLine("[Events]");

if (!string.IsNullOrEmpty(beatmap.BeatmapInfo.Metadata.BackgroundFile))
writer.WriteLine(FormattableString.Invariant($"{(int)LegacyEventType.Background},0,\"{beatmap.BeatmapInfo.Metadata.BackgroundFile}\",0,0"));
{
var metadata = beatmap.BeatmapInfo.Metadata;
writer.WriteLine(FormattableString.Invariant($"{(int)LegacyEventType.Background},0,\"{metadata.BackgroundFile}\",{metadata.BackgroundOffsetX},{metadata.BackgroundOffsetY}"));
}

foreach (var b in beatmap.Breaks)
writer.WriteLine(FormattableString.Invariant($"{(int)LegacyEventType.Break},{b.StartTime},{b.EndTime}"));
Expand Down
14 changes: 13 additions & 1 deletion osu.Game/Beatmaps/IBeatmapMetadataInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ public interface IBeatmapMetadataInfo : IEquatable<IBeatmapMetadataInfo>
/// </summary>
string BackgroundFile { get; }

/// <summary>
/// Horizontal offset in pixels of the legacy Background event (fourth column in <c>[Events]</c>).
/// </summary>
float BackgroundOffsetX { get; }

/// <summary>
/// Vertical offset in pixels of the legacy Background event (fifth column in <c>[Events]</c>).
/// </summary>
float BackgroundOffsetY { get; }

bool IEquatable<IBeatmapMetadataInfo>.Equals(IBeatmapMetadataInfo? other)
{
if (other == null)
Expand All @@ -76,7 +86,9 @@ bool IEquatable<IBeatmapMetadataInfo>.Equals(IBeatmapMetadataInfo? other)
&& Tags == other.Tags
&& PreviewTime == other.PreviewTime
&& AudioFile == other.AudioFile
&& BackgroundFile == other.BackgroundFile;
&& BackgroundFile == other.BackgroundFile
&& BackgroundOffsetX.Equals(other.BackgroundOffsetX)
&& BackgroundOffsetY.Equals(other.BackgroundOffsetY);
}
}
}
3 changes: 2 additions & 1 deletion osu.Game/Database/RealmAccess.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,9 @@ public class RealmAccess : IDisposable
/// 49 2025-06-10 Reset the LegacyOnlineID to -1 for all scores that have it set to 0 (which is semantically the same) for consistency of handling with OnlineID.
/// 50 2025-07-11 Add UserTags to BeatmapMetadata.
/// 51 2025-07-22 Add ScoreInfo.Pauses.
/// 52 2026-04-21 Add Background offset fields to BeatmapMetadata.
/// </summary>
private const int schema_version = 51;
private const int schema_version = 52;

/// <summary>
/// Lock object which is held during <see cref="BlockAllOperations"/> sections, blocking realm retrieval during blocking periods.
Expand Down
Loading