diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardEncoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardEncoderTest.cs
index ad6d0fb7c3..1b340ddd24 100644
--- a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardEncoderTest.cs
+++ b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardEncoderTest.cs
@@ -30,6 +30,23 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.That(decodedAfterEncode.Beatmap.BeatmapInfo.Metadata.BackgroundFile, Is.EqualTo("bg.jpg"));
}
+ [Test]
+ public void TestBackgroundOffset()
+ {
+ var initial = createComponents();
+ initial.Beatmap.BeatmapInfo.Metadata.BackgroundFile = "bg_offset.jpg";
+ initial.Storyboard.BackgroundOffset = new Vector2(0, 45);
+
+ var encoded = encode(initial);
+ var decodedAfterEncode = decode(encoded);
+
+ Assert.Multiple(() =>
+ {
+ Assert.That(decodedAfterEncode.Beatmap.BeatmapInfo.Metadata.BackgroundFile, Is.EqualTo("bg_offset.jpg"));
+ Assert.That(decodedAfterEncode.Storyboard.BackgroundOffset, Is.EqualTo(new Vector2(0, 45)));
+ });
+ }
+
[Test]
public void TestVideos()
{
diff --git a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs
index eb1dacb447..563ef78362 100644
--- a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs
+++ b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs
@@ -120,6 +120,20 @@ namespace osu.Game.Beatmaps.Formats
switch (type)
{
+ case LegacyEventType.Background:
+ {
+ // the actual filename is handled in `LegacyBeatmapDecoder`.
+ // this only handles the background offset, because it does not logically belong in `Beatmap` or related classes.
+ if (split.Length > 4)
+ {
+ float x = Parsing.ParseFloat(split[3]);
+ float y = Parsing.ParseFloat(split[4]);
+ storyboard.BackgroundOffset = new Vector2(x, y);
+ }
+
+ break;
+ }
+
case LegacyEventType.Video:
{
int offset = Parsing.ParseInt(split[1]);
diff --git a/osu.Game/Beatmaps/Formats/LegacyStoryboardEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyStoryboardEncoder.cs
index 7238f2e7af..09148899e7 100644
--- a/osu.Game/Beatmaps/Formats/LegacyStoryboardEncoder.cs
+++ b/osu.Game/Beatmaps/Formats/LegacyStoryboardEncoder.cs
@@ -54,10 +54,9 @@ namespace osu.Game.Beatmaps.Formats
if (target == StoryboardElementSource.Beatmap)
{
// https://github.com/peppy/osu-stable-reference/blob/c34a74fb61c17c5667486a12548485d1f03baa2e/osu!/GameplayElements/HitObjectManager_LoadSave.cs#L1499
- // TODO: handle nonzero background offset (https://github.com/ppy/osu/issues/14238)
writer.WriteLine(string.Format(CultureInfo.InvariantCulture,
@"{0},{1},""{2}"",{3},{4}",
- (int)LegacyEventType.Background, 0, storyboard.BeatmapInfo.Metadata.BackgroundFile, 0, 0));
+ (int)LegacyEventType.Background, 0, storyboard.BeatmapInfo.Metadata.BackgroundFile, storyboard.BackgroundOffset.X, storyboard.BackgroundOffset.Y));
}
// https://github.com/peppy/osu-stable-reference/blob/c34a74fb61c17c5667486a12548485d1f03baa2e/osu!/GameplayElements/HitObjectManager_LoadSave.cs#L1496
diff --git a/osu.Game/Storyboards/Storyboard.cs b/osu.Game/Storyboards/Storyboard.cs
index 4dc96c84a4..d3c10aa162 100644
--- a/osu.Game/Storyboards/Storyboard.cs
+++ b/osu.Game/Storyboards/Storyboard.cs
@@ -9,6 +9,7 @@ using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mods;
using osu.Game.Storyboards.Drawables;
using osu.Game.Utils;
+using osuTK;
namespace osu.Game.Storyboards
{
@@ -98,6 +99,12 @@ namespace osu.Game.Storyboards
}
}
+ ///
+ /// Offset to be applied to the beatmap background.
+ /// TODO: Unused yet. See https://github.com/ppy/osu/issues/14238.
+ ///
+ public Vector2 BackgroundOffset { get; set; } = Vector2.Zero;
+
public virtual DrawableStoryboard CreateDrawable(IReadOnlyList? mods = null) =>
new DrawableStoryboard(this, mods);