diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs index d9e80fa111..281ea4e4ff 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs @@ -214,7 +214,9 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.That(oneTime.EndTime, Is.EqualTo(4000 + loop_duration)); StoryboardSprite manyTimes = background.Elements.OfType().Single(s => s.Path == "many-times.png"); - Assert.That(manyTimes.EndTime, Is.EqualTo(9000 + 40 * loop_duration)); + // It is intentional that we don't consider the loop count (40) as part of the end time calculation to match stable's handling. + // If we were to include the loop count, storyboards which loop for stupid long loop counts would continue playing the outro forever. + Assert.That(manyTimes.EndTime, Is.EqualTo(9000 + loop_duration)); } } } diff --git a/osu.Game/Storyboards/CommandLoop.cs b/osu.Game/Storyboards/CommandLoop.cs index 0f26ed2c66..29e034d86c 100644 --- a/osu.Game/Storyboards/CommandLoop.cs +++ b/osu.Game/Storyboards/CommandLoop.cs @@ -18,7 +18,12 @@ namespace osu.Game.Storyboards public readonly int TotalIterations; public override double StartTime => LoopStartTime + CommandsStartTime; - public override double EndTime => StartTime + CommandsDuration * TotalIterations; + + public override double EndTime => + // In an ideal world, we would multiply the command duration by TotalIterations here. + // Unfortunately this would clash with how stable handled end times, and results in some storyboards playing outro + // sequences for minutes or hours. + StartTime + CommandsDuration; /// /// Construct a new command loop.