<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.

using osu.Framework.Audio;
using osu.Framework.Bindables;
using osu.Game.Rulesets.UI;
using System;
using System.Collections.Generic;
using ManagedBass.Fx;
using osu.Framework.Allocation;
using osu.Framework.Audio.Sample;
using osu.Framework.Audio.Track;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Utils;
using osu.Game.Audio.Effects;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Rulesets.Objects.Drawables;
using osuTK;
using osuTK.Graphics;

namespace osu.Game.Screens.Play
{
    /// <summary>
    /// Manage the animation to be applied when a player fails.
    /// Single use and automatically disposed after use.
    /// </summary>
    public class FailAnimation : Container
    {
        public Action? OnComplete;

        private readonly DrawableRuleset drawableRuleset;
        private readonly BindableDouble trackFreq = new BindableDouble(1);
        private readonly BindableDouble volumeAdjustment = new BindableDouble(0.5);

        private Container filters = null!;

        private Box redFlashLayer = null!;

        private Track track = null!;

        private AudioFilter failLowPassFilter = null!;
        private AudioFilter failHighPassFilter = null!;

        private const float duration = 2500;

        private Sample? failSample;

        [Resolved]
        private OsuConfigManager config { get; set; } = null!;

        protected override Container<Drawable> Content { get; } = new Container
        {
            Anchor = Anchor.Centre,
            Origin = Anchor.Centre,
            RelativeSizeAxes = Axes.Both,
        };

        /// <summary>
        /// The player screen background, used to adjust appearance on failing.
        /// </summary>
        public BackgroundScreen? Background { private get; set; }

        public FailAnimation(DrawableRuleset drawableRuleset)
        {
            this.drawableRuleset = drawableRuleset;

            RelativeSizeAxes = Axes.Both;
        }

        [BackgroundDependencyLoader]
        private void load(AudioManager audio, IBindable<WorkingBeatmap> beatmap)
        {
            track = beatmap.Value.Track;
            failSample = audio.Samples.Get(@"Gameplay/failsound");

            AddRangeInternal(new Drawable[]
            {
                filters = new Container
                {
                    Children = new Drawable[]
                    {
                        failLowPassFilter = new AudioFilter(audio.TrackMixer),
                        failHighPassFilter = new AudioFilter(audio.TrackMixer, BQFType.HighPass),
                    },
                },
                Content,
                redFlashLayer = new Box
                {
                    Colour = Color4.Red.Opacity(0.6f),
                    RelativeSizeAxes = Axes.Both,
                    Blending = BlendingParameters.Additive,
                    Depth = float.MinValue,
                    Alpha = 0
                },
            });
        }

        private bool started;
        private bool filtersRemoved;

        /// <summary>
        /// Start the fail animation playing.
        /// </summary>
        /// <exception cref="InvalidOperationException">Thrown if started more than once.</exception>
        public void Start()
        {
            if (started) throw new InvalidOperationException("Animation cannot be started more than once.");
            if (filtersRemoved) throw new InvalidOperationException("Animation cannot be started after filters have been removed.");

            started = true;

            this.TransformBindableTo(trackFreq, 0, duration).OnComplete(_ =>
            {
                // Don't reset frequency as the pause screen may appear post transform, causing a second frequency sweep.
                RemoveFilters(false);
                OnComplete?.Invoke();
            });

            failHighPassFilter.CutoffTo(300);
            failLowPassFilter.CutoffTo(300, duration, Easing.OutCubic);
            failSample?.Play();

            track.AddAdjustment(AdjustableProperty.Frequency, trackFreq);
            track.AddAdjustment(AdjustableProperty.Volume, volumeAdjustment);

            applyToPlayfield(drawableRuleset.Playfield);
            drawableRuleset.Playfield.HitObjectContainer.FadeOut(duration / 2);

            if (config.Get<bool>(OsuSetting.FadePlayfieldWhenHealthLow))
                redFlashLayer.FadeOutFromOne(1000);

            Content.Masking = true;

            Content.Add(new Box
            {
                Colour = Color4.Black,
                RelativeSizeAxes = Axes.Both,
                Depth = float.MaxValue
            });

            Content.ScaleTo(0.85f, duration, Easing.OutQuart);
            Content.RotateTo(1, duration, Easing.OutQuart);
            Content.FadeColour(Color4.Gray, duration);

            // Will be restored by `ApplyToBackground` logic in `SongSelect`.
            Background?.FadeColour(OsuColour.Gray(0.3f), 60);
        }

        public void RemoveFilters(bool resetTrackFrequency = true)
        {
            if (filtersRemoved) return;

            filtersRemoved = true;

            if (!started)
                return;

            if (resetTrackFrequency)
                track.RemoveAdjustment(AdjustableProperty.Frequency, trackFreq);

            track.RemoveAdjustment(AdjustableProperty.Volume, volumeAdjustment);

            if (filters.Parent == null)
                return;

            RemoveInternal(filters);
            filters.Dispose();
        }

        protected override void Update()
        {
            base.Update();

            if (!started)
                return;

            applyToPlayfield(drawableRuleset.Playfield);
        }
<commit_msg>Remove guard against `RemoveFilters` running more than once<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.

using osu.Framework.Audio;
using osu.Framework.Bindables;
using osu.Game.Rulesets.UI;
using System;
using System.Collections.Generic;
using ManagedBass.Fx;
using osu.Framework.Allocation;
using osu.Framework.Audio.Sample;
using osu.Framework.Audio.Track;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Utils;
using osu.Game.Audio.Effects;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Rulesets.Objects.Drawables;
using osuTK;
using osuTK.Graphics;

namespace osu.Game.Screens.Play
{
    /// <summary>
    /// Manage the animation to be applied when a player fails.
    /// Single use and automatically disposed after use.
    /// </summary>
    public class FailAnimation : Container
    {
        public Action? OnComplete;

        private readonly DrawableRuleset drawableRuleset;
        private readonly BindableDouble trackFreq = new BindableDouble(1);
        private readonly BindableDouble volumeAdjustment = new BindableDouble(0.5);

        private Container filters = null!;

        private Box redFlashLayer = null!;

        private Track track = null!;

        private AudioFilter failLowPassFilter = null!;
        private AudioFilter failHighPassFilter = null!;

        private const float duration = 2500;

        private Sample? failSample;

        [Resolved]
        private OsuConfigManager config { get; set; } = null!;

        protected override Container<Drawable> Content { get; } = new Container
        {
            Anchor = Anchor.Centre,
            Origin = Anchor.Centre,
            RelativeSizeAxes = Axes.Both,
        };

        /// <summary>
        /// The player screen background, used to adjust appearance on failing.
        /// </summary>
        public BackgroundScreen? Background { private get; set; }

        public FailAnimation(DrawableRuleset drawableRuleset)
        {
            this.drawableRuleset = drawableRuleset;

            RelativeSizeAxes = Axes.Both;
        }

        [BackgroundDependencyLoader]
        private void load(AudioManager audio, IBindable<WorkingBeatmap> beatmap)
        {
            track = beatmap.Value.Track;
            failSample = audio.Samples.Get(@"Gameplay/failsound");

            AddRangeInternal(new Drawable[]
            {
                filters = new Container
                {
                    Children = new Drawable[]
                    {
                        failLowPassFilter = new AudioFilter(audio.TrackMixer),
                        failHighPassFilter = new AudioFilter(audio.TrackMixer, BQFType.HighPass),
                    },
                },
                Content,
                redFlashLayer = new Box
                {
                    Colour = Color4.Red.Opacity(0.6f),
                    RelativeSizeAxes = Axes.Both,
                    Blending = BlendingParameters.Additive,
                    Depth = float.MinValue,
                    Alpha = 0
                },
            });
        }

        private bool started;
        private bool filtersRemoved;

        /// <summary>
        /// Start the fail animation playing.
        /// </summary>
        /// <exception cref="InvalidOperationException">Thrown if started more than once.</exception>
        public void Start()
        {
            if (started) throw new InvalidOperationException("Animation cannot be started more than once.");
            if (filtersRemoved) throw new InvalidOperationException("Animation cannot be started after filters have been removed.");

            started = true;

            this.TransformBindableTo(trackFreq, 0, duration).OnComplete(_ =>
            {
                // Don't reset frequency as the pause screen may appear post transform, causing a second frequency sweep.
                RemoveFilters(false);
                OnComplete?.Invoke();
            });

            failHighPassFilter.CutoffTo(300);
            failLowPassFilter.CutoffTo(300, duration, Easing.OutCubic);
            failSample?.Play();

            track.AddAdjustment(AdjustableProperty.Frequency, trackFreq);
            track.AddAdjustment(AdjustableProperty.Volume, volumeAdjustment);

            applyToPlayfield(drawableRuleset.Playfield);
            drawableRuleset.Playfield.HitObjectContainer.FadeOut(duration / 2);

            if (config.Get<bool>(OsuSetting.FadePlayfieldWhenHealthLow))
                redFlashLayer.FadeOutFromOne(1000);

            Content.Masking = true;

            Content.Add(new Box
            {
                Colour = Color4.Black,
                RelativeSizeAxes = Axes.Both,
                Depth = float.MaxValue
            });

            Content.ScaleTo(0.85f, duration, Easing.OutQuart);
            Content.RotateTo(1, duration, Easing.OutQuart);
            Content.FadeColour(Color4.Gray, duration);

            // Will be restored by `ApplyToBackground` logic in `SongSelect`.
            Background?.FadeColour(OsuColour.Gray(0.3f), 60);
        }

        public void RemoveFilters(bool resetTrackFrequency = true)
        {
            filtersRemoved = true;

            if (!started)
                return;

            if (resetTrackFrequency)
                track.RemoveAdjustment(AdjustableProperty.Frequency, trackFreq);

            track.RemoveAdjustment(AdjustableProperty.Volume, volumeAdjustment);

            if (filters.Parent == null)
                return;

            RemoveInternal(filters);
            filters.Dispose();
        }

        protected override void Update()
        {
            base.Update();

            if (!started)
                return;

            applyToPlayfield(drawableRuleset.Playfield);
        }

{'fraction_non_alphanumeric': 0.08436128818610812, 'fraction_numerical': 0.005629605099759914, 'mean_word_length': 1.962236390387445, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 31, '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': '2750248', 'n_tokens_mistral': 3216, 'n_tokens_neox': 2981, 'n_words': 748}