<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 System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Logging;
using osu.Framework.Timing;
using osu.Framework.Utils;
using osu.Game.Beatmaps;

namespace osu.Game.Screens.Play
{
    /// <summary>
    /// Encapsulates gameplay timing logic and provides a <see cref="IGameplayClock"/> via DI for gameplay components to use.
    /// </summary>
    [Cached(typeof(IGameplayClock))]
    public class GameplayClockContainer : Container, IAdjustableClock, IGameplayClock
    {
        /// <summary>
        /// Whether gameplay is paused.
        /// </summary>
        public IBindable<bool> IsPaused => isPaused;

        /// <summary>
        /// The source clock. Should generally not be used for any timekeeping purposes.
        /// </summary>
        public IClock SourceClock { get; private set; }

        /// <summary>
        /// Invoked when a seek has been performed via <see cref="Seek"/>
        /// </summary>
        public event Action? OnSeek;

        /// <summary>
        /// The time from which the clock should start. Will be seeked to on calling <see cref="Reset"/>.
        /// Can be adjusted by calling <see cref="Reset"/> with a time value.
        /// </summary>
        /// <remarks>
        /// By default, a value of zero will be used.
        /// Importantly, the value will be inferred from the current beatmap in <see cref="MasterGameplayClockContainer"/> by default.
        /// </remarks>
        public double StartTime { get; protected set; }

        public virtual IEnumerable<double> NonGameplayAdjustments => Enumerable.Empty<double>();

        private readonly BindableBool isPaused = new BindableBool(true);

        /// <summary>
        /// The adjustable source clock used for gameplay. Should be used for seeks and clock control.
        /// This is the final source exposed to gameplay components <see cref="IGameplayClock"/> via delegation in this class.
        /// </summary>
        protected readonly FramedBeatmapClock GameplayClock;

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

        /// <summary>
        /// Creates a new <see cref="GameplayClockContainer"/>.
        /// </summary>
        /// <param name="sourceClock">The source <see cref="IClock"/> used for timing.</param>
        /// <param name="applyOffsets">Whether to apply platform, user and beatmap offsets to the mix.</param>
        public GameplayClockContainer(IClock sourceClock, bool applyOffsets = false)
        {
            SourceClock = sourceClock;

            RelativeSizeAxes = Axes.Both;

            InternalChildren = new Drawable[]
            {
                GameplayClock = new FramedBeatmapClock(applyOffsets) { IsCoupled = false },
                Content
            };
        }

        /// <summary>
        /// Starts gameplay and marks un-paused state.
        /// </summary>
        public void Start()
        {
            if (!isPaused.Value)
                return;

            isPaused.Value = false;

            ensureSourceClockSet();

            PrepareStart();

            // The case which caused this to be added is FrameStabilityContainer, which manages its own current and elapsed time.
            // Because we generally update our own current time quicker than children can query it (via Start/Seek/Update),
            // this means that the first frame ever exposed to children may have a non-zero current time.
            //
            // If the child component is not aware of the parent ElapsedFrameTime (which is the case for FrameStabilityContainer)
            // they will take on the new CurrentTime with a zero elapsed time. This can in turn cause components to behave incorrectly
            // if they are intending to trigger events at the precise StartTime (ie. DrawableStoryboardSample).
            //
            // By scheduling the start call, children are guaranteed to receive one frame at the original start time, allowing
            // then to progress with a correct locally calculated elapsed time.
            SchedulerAfterChildren.Add(() =>
            {
                if (isPaused.Value)
                    return;

                StartGameplayClock();
            });
        }

        /// <summary>
        /// When <see cref="Start"/> is called, this will be run to give an opportunity to prepare the clock at the correct
        /// start location.
        /// </summary>
        protected virtual void PrepareStart()
        {
            // Seeking the decoupled clock to its current time ensures that its source clock will be seeked to the same time
            // This accounts for the clock source potentially taking time to enter a completely stopped state
            Seek(GameplayClock.CurrentTime);
        }

        /// <summary>
        /// Seek to a specific time in gameplay.
        /// </summary>
        /// <param name="time">The destination time to seek to.</param>
        public virtual void Seek(double time)
        {
            Logger.Log($"{nameof(GameplayClockContainer)} seeking to {time}");

            GameplayClock.Seek(time);

            OnSeek?.Invoke();
        }
<commit_msg>Remove probably unnecessary `Seek` on start<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 System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Logging;
using osu.Framework.Timing;
using osu.Framework.Utils;
using osu.Game.Beatmaps;

namespace osu.Game.Screens.Play
{
    /// <summary>
    /// Encapsulates gameplay timing logic and provides a <see cref="IGameplayClock"/> via DI for gameplay components to use.
    /// </summary>
    [Cached(typeof(IGameplayClock))]
    public class GameplayClockContainer : Container, IAdjustableClock, IGameplayClock
    {
        /// <summary>
        /// Whether gameplay is paused.
        /// </summary>
        public IBindable<bool> IsPaused => isPaused;

        /// <summary>
        /// The source clock. Should generally not be used for any timekeeping purposes.
        /// </summary>
        public IClock SourceClock { get; private set; }

        /// <summary>
        /// Invoked when a seek has been performed via <see cref="Seek"/>
        /// </summary>
        public event Action? OnSeek;

        /// <summary>
        /// The time from which the clock should start. Will be seeked to on calling <see cref="Reset"/>.
        /// Can be adjusted by calling <see cref="Reset"/> with a time value.
        /// </summary>
        /// <remarks>
        /// By default, a value of zero will be used.
        /// Importantly, the value will be inferred from the current beatmap in <see cref="MasterGameplayClockContainer"/> by default.
        /// </remarks>
        public double StartTime { get; protected set; }

        public virtual IEnumerable<double> NonGameplayAdjustments => Enumerable.Empty<double>();

        private readonly BindableBool isPaused = new BindableBool(true);

        /// <summary>
        /// The adjustable source clock used for gameplay. Should be used for seeks and clock control.
        /// This is the final source exposed to gameplay components <see cref="IGameplayClock"/> via delegation in this class.
        /// </summary>
        protected readonly FramedBeatmapClock GameplayClock;

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

        /// <summary>
        /// Creates a new <see cref="GameplayClockContainer"/>.
        /// </summary>
        /// <param name="sourceClock">The source <see cref="IClock"/> used for timing.</param>
        /// <param name="applyOffsets">Whether to apply platform, user and beatmap offsets to the mix.</param>
        public GameplayClockContainer(IClock sourceClock, bool applyOffsets = false)
        {
            SourceClock = sourceClock;

            RelativeSizeAxes = Axes.Both;

            InternalChildren = new Drawable[]
            {
                GameplayClock = new FramedBeatmapClock(applyOffsets) { IsCoupled = false },
                Content
            };
        }

        /// <summary>
        /// Starts gameplay and marks un-paused state.
        /// </summary>
        public void Start()
        {
            if (!isPaused.Value)
                return;

            isPaused.Value = false;

            ensureSourceClockSet();

            PrepareStart();

            // The case which caused this to be added is FrameStabilityContainer, which manages its own current and elapsed time.
            // Because we generally update our own current time quicker than children can query it (via Start/Seek/Update),
            // this means that the first frame ever exposed to children may have a non-zero current time.
            //
            // If the child component is not aware of the parent ElapsedFrameTime (which is the case for FrameStabilityContainer)
            // they will take on the new CurrentTime with a zero elapsed time. This can in turn cause components to behave incorrectly
            // if they are intending to trigger events at the precise StartTime (ie. DrawableStoryboardSample).
            //
            // By scheduling the start call, children are guaranteed to receive one frame at the original start time, allowing
            // then to progress with a correct locally calculated elapsed time.
            SchedulerAfterChildren.Add(() =>
            {
                if (isPaused.Value)
                    return;

                StartGameplayClock();
            });
        }

        /// <summary>
        /// When <see cref="Start"/> is called, this will be run to give an opportunity to prepare the clock at the correct
        /// start location.
        /// </summary>
        protected virtual void PrepareStart()
        {
        }

        /// <summary>
        /// Seek to a specific time in gameplay.
        /// </summary>
        /// <param name="time">The destination time to seek to.</param>
        public virtual void Seek(double time)
        {
            Logger.Log($"{nameof(GameplayClockContainer)} seeking to {time}");

            GameplayClock.Seek(time);

            OnSeek?.Invoke();
        }

{'fraction_non_alphanumeric': 0.09490268767377201, 'fraction_numerical': 0.0, 'mean_word_length': 2.073483338080319, 'pattern_counts': {'":': 0, '<': 89, '<?xml version=': 0, '>': 95, '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': '3513208', 'n_tokens_mistral': 2728, 'n_tokens_neox': 2600, 'n_words': 1021}