<commit_before>// Copyright (c) ppy Pty Ltd <<EMAIL>>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

#nullable enable

using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Overlays;
using osu.Game.Storyboards.Drawables;

namespace osu.Game.Graphics.Backgrounds
{
    public class BeatmapBackgroundWithStoryboard : BeatmapBackground
    {
        private InterpolatingFramedClock storyboardClock = null!;

        [Resolved(CanBeNull = true)]
        private MusicController? musicController { get; set; }

        public BeatmapBackgroundWithStoryboard(WorkingBeatmap beatmap, string fallbackTextureName = "Backgrounds/bg1")
            : base(beatmap, fallbackTextureName)
        {
        }

        [BackgroundDependencyLoader]
        private void load()
        {
            if (!Beatmap.Storyboard.HasDrawable)
                return;

            if (Beatmap.Storyboard.ReplacesBackground)
                Sprite.Alpha = 0;

            LoadComponentAsync(new AudioContainer
            {
                RelativeSizeAxes = Axes.Both,
                Volume = { Value = 0 },
                Child = new DrawableStoryboard(Beatmap.Storyboard) { Clock = storyboardClock = new InterpolatingFramedClock(Beatmap.Track) }
            }, AddInternal);
        }

        protected override void LoadComplete()
        {
            base.LoadComplete();
            if (musicController != null)
                musicController.TrackChanged += onTrackChanged;
        }

        private void onTrackChanged(WorkingBeatmap newBeatmap, TrackChangeDirection _)
        {
            if (newBeatmap != Beatmap)
                return;

            // `MusicController` will sometimes reload the track, even when the working beatmap technically hasn't changed.
            // ensure that the storyboard's clock is always using the latest track instance.
            storyboardClock.ChangeSource(newBeatmap.Track);
            // more often than not, the previous source track's time will be in the future relative to the new source track.
            // explicitly process a single frame so that `InterpolatingFramedClock`'s interpolation logic is bypassed
            // and the storyboard clock is correctly rewound to the source track's time exactly.
            storyboardClock.ProcessFrame();
        }

        protected override void Dispose(bool isDisposing)
        {
            base.Dispose(isDisposing);
            if (musicController != null)
                musicController.TrackChanged -= onTrackChanged;
        }
    }
}<commit_msg>Rewrite storyboard clock management in slightly different way<commit_after>// Copyright (c) ppy Pty Ltd <<EMAIL>>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

#nullable enable

using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Overlays;
using osu.Game.Storyboards.Drawables;

namespace osu.Game.Graphics.Backgrounds
{
    public class BeatmapBackgroundWithStoryboard : BeatmapBackground
    {
        private readonly InterpolatingFramedClock storyboardClock;

        [Resolved(CanBeNull = true)]
        private MusicController? musicController { get; set; }

        public BeatmapBackgroundWithStoryboard(WorkingBeatmap beatmap, string fallbackTextureName = "Backgrounds/bg1")
            : base(beatmap, fallbackTextureName)
        {
            storyboardClock = new InterpolatingFramedClock();
        }

        [BackgroundDependencyLoader]
        private void load()
        {
            if (!Beatmap.Storyboard.HasDrawable)
                return;

            if (Beatmap.Storyboard.ReplacesBackground)
                Sprite.Alpha = 0;

            LoadComponentAsync(new AudioContainer
            {
                RelativeSizeAxes = Axes.Both,
                Volume = { Value = 0 },
                Child = new DrawableStoryboard(Beatmap.Storyboard) { Clock = storyboardClock }
            }, AddInternal);
        }

        protected override void LoadComplete()
        {
            base.LoadComplete();
            if (musicController != null)
                musicController.TrackChanged += onTrackChanged;

            updateStoryboardClockSource(Beatmap);
        }

        private void onTrackChanged(WorkingBeatmap newBeatmap, TrackChangeDirection _) => updateStoryboardClockSource(newBeatmap);

        private void updateStoryboardClockSource(WorkingBeatmap newBeatmap)
        {
            if (newBeatmap != Beatmap)
                return;

            // `MusicController` will sometimes reload the track, even when the working beatmap technically hasn't changed.
            // ensure that the storyboard's clock is always using the latest track instance.
            storyboardClock.ChangeSource(newBeatmap.Track);
            // more often than not, the previous source track's time will be in the future relative to the new source track.
            // explicitly process a single frame so that `InterpolatingFramedClock`'s interpolation logic is bypassed
            // and the storyboard clock is correctly rewound to the source track's time exactly.
            storyboardClock.ProcessFrame();
        }

        protected override void Dispose(bool isDisposing)
        {
            base.Dispose(isDisposing);
            if (musicController != null)
                musicController.TrackChanged -= onTrackChanged;
        }
    }
}
{'fraction_non_alphanumeric': 0.0697551523692091, 'fraction_numerical': 0.0010568962480183195, 'mean_word_length': 2.3797619047619047, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2496236', 'n_tokens_mistral': 1485, 'n_tokens_neox': 1370, 'n_words': 402}