// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; using osu.Framework.Bindables; using osu.Framework.Timing; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { /// /// A which catches up using rate adjustment. /// public class CatchUpSpectatorPlayerClock : ISpectatorPlayerClock { /// /// The catch up rate. /// public const double CATCHUP_RATE = 2; public IFrameBasedClock Source { get; set; } public double CurrentTime { get; private set; } public bool IsRunning { get; private set; } public CatchUpSpectatorPlayerClock(IFrameBasedClock source) { Source = source; } public void Reset() => CurrentTime = 0; public void Start() => IsRunning = true; public void Stop() => IsRunning = false; void IAdjustableClock.Start() { // Our running state should only be managed by an ISyncManager, ignore calls from external sources. } void IAdjustableClock.Stop() { // Our running state should only be managed by an ISyncManager, ignore calls from external sources. } public bool Seek(double position) { CurrentTime = position; return true; } public void ResetSpeedAdjustments() { } public double Rate => IsCatchingUp ? CATCHUP_RATE : 1; double IAdjustableClock.Rate { get => Rate; set => throw new NotSupportedException(); } double IClock.Rate => Rate; public void ProcessFrame() { ElapsedFrameTime = 0; FramesPerSecond = 0; Source.ProcessFrame(); if (IsRunning) { double elapsedSource = Source.ElapsedFrameTime; double elapsed = elapsedSource * Rate; CurrentTime += elapsed; ElapsedFrameTime = elapsed; FramesPerSecond = Source.FramesPerSecond; } } public double ElapsedFrameTime { get; private set; } public double FramesPerSecond { get; private set; } public FrameTimeInfo TimeInfo => new FrameTimeInfo { Elapsed = ElapsedFrameTime, Current = CurrentTime }; public Bindable WaitingOnFrames { get; } = new Bindable(true); public bool IsCatchingUp { get; set; } } }