diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index e75e5cc5f3..e41802808f 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -22,9 +22,9 @@ namespace osu.Game.Rulesets.UI /// [Cached(typeof(IGameplayClock))] [Cached(typeof(IFrameStableClock))] - public class FrameStabilityContainer : Container, IHasReplayHandler, IFrameStableClock, IGameplayClock + public sealed class FrameStabilityContainer : Container, IHasReplayHandler, IFrameStableClock, IGameplayClock { - private readonly double gameplayStartTime; + public ReplayInputHandler? ReplayInputHandler { get; set; } /// /// The number of frames (per parent frame) which can be run in an attempt to catch-up to real-time. @@ -34,13 +34,48 @@ namespace osu.Game.Rulesets.UI /// /// Whether to enable frame-stable playback. /// - internal bool FrameStablePlayback = true; + internal bool FrameStablePlayback { get; set; } = true; - public readonly Bindable IsCatchingUp = new Bindable(); + protected override bool RequiresChildrenUpdate => base.RequiresChildrenUpdate && state != PlaybackState.NotValid; - public readonly Bindable WaitingOnFrames = new Bindable(); + private readonly Bindable isCatchingUp = new Bindable(); - public IBindable IsPaused { get; } = new BindableBool(); + private readonly Bindable waitingOnFrames = new Bindable(); + + private readonly double gameplayStartTime; + + private IGameplayClock? parentGameplayClock; + + /// + /// A clock which is used as reference for time, rate and running state. + /// + private IClock referenceClock = null!; + + /// + /// A local manual clock which tracks the reference clock. + /// Values are transferred from each update call. + /// + private readonly ManualClock manualClock; + + /// + /// The main framed clock which has stability applied to it. + /// This gets exposed to children as an . + /// + private readonly FramedClock framedClock; + + /// + /// The current direction of playback to be exposed to frame stable children. + /// + /// + /// Initially it is presumed that playback will proceed in the forward direction. + /// + private int direction = 1; + + private PlaybackState state; + + private bool hasReplayAttached => ReplayInputHandler != null; + + private bool firstConsumption = true; public FrameStabilityContainer(double gameplayStartTime = double.MinValue) { @@ -51,22 +86,6 @@ namespace osu.Game.Rulesets.UI this.gameplayStartTime = gameplayStartTime; } - private readonly ManualClock manualClock; - - private readonly FramedClock framedClock; - - private IGameplayClock? parentGameplayClock; - - private IClock referenceClock = null!; - - /// - /// The current direction of playback to be exposed to frame stable children. - /// - /// - /// Initially it is presumed that playback will proceed in the forward direction. - /// - private int direction = 1; - [BackgroundDependencyLoader] private void load(IGameplayClock? gameplayClock) { @@ -80,16 +99,6 @@ namespace osu.Game.Rulesets.UI Clock = this; } - private PlaybackState state; - - protected override bool RequiresChildrenUpdate => base.RequiresChildrenUpdate && state != PlaybackState.NotValid; - - private bool hasReplayAttached => ReplayInputHandler != null; - - private const double sixty_frame_time = 1000.0 / 60; - - private bool firstConsumption = true; - public override bool UpdateSubTree() { int loops = MaxCatchUpFrames; @@ -112,7 +121,7 @@ namespace osu.Game.Rulesets.UI private void updateClock() { - if (WaitingOnFrames.Value) + if (waitingOnFrames.Value) { // if waiting on frames, run one update loop to determine if frames have arrived. state = PlaybackState.Valid; @@ -150,8 +159,8 @@ namespace osu.Game.Rulesets.UI double timeBehind = Math.Abs(proposedTime - referenceClock.CurrentTime); - IsCatchingUp.Value = timeBehind > 200; - WaitingOnFrames.Value = state == PlaybackState.NotValid; + isCatchingUp.Value = timeBehind > 200; + waitingOnFrames.Value = state == PlaybackState.NotValid; manualClock.CurrentTime = proposedTime; manualClock.Rate = Math.Abs(referenceClock.Rate) * direction; @@ -211,6 +220,8 @@ namespace osu.Game.Rulesets.UI /// The time which is to be displayed. private void applyFrameStability(ref double proposedTime) { + const double sixty_frame_time = 1000.0 / 60; + if (firstConsumption) { // On the first update, frame-stability seeking would result in unexpected/unwanted behaviour. @@ -234,9 +245,9 @@ namespace osu.Game.Rulesets.UI } } - public ReplayInputHandler? ReplayInputHandler { get; set; } + #region Delegation of IGameplayClock - #region Delegation of IFrameStableClock + public IBindable IsPaused { get; } = new BindableBool(); public double CurrentTime => framedClock.CurrentTime; @@ -252,10 +263,6 @@ namespace osu.Game.Rulesets.UI public FrameTimeInfo TimeInfo => framedClock.TimeInfo; - #endregion - - #region Delegation of IGameplayClock - public double TrueGameplayRate { get @@ -280,6 +287,13 @@ namespace osu.Game.Rulesets.UI #endregion + #region Delegation of IFrameStableClock + + IBindable IFrameStableClock.IsCatchingUp => isCatchingUp; + IBindable IFrameStableClock.WaitingOnFrames => waitingOnFrames; + + #endregion + private enum PlaybackState { /// @@ -298,8 +312,5 @@ namespace osu.Game.Rulesets.UI /// Valid } - - IBindable IFrameStableClock.IsCatchingUp => IsCatchingUp; - IBindable IFrameStableClock.WaitingOnFrames => WaitingOnFrames; } }