using System; using JetBrains.Annotations; using Robust.Shared.GameObjects; using Robust.Shared.IoC; namespace Robust.Shared.Timing { /// /// This holds main loop timing information and helper functions. /// [NotContentImplementable] public interface IGameTiming { /// /// Is program execution inside the simulation, or outside of it (rendering, input handling, etc.) /// bool InSimulation { get; set; } /// /// Is the simulation currently paused? /// /// /// When true, system update loops are not ran and relative time (like ) does not /// advance. This is useful for fully idling a game server and can be automatically managed by /// . /// bool Paused { get; set; } /// /// The current synchronized uptime of the simulation. Use this for in-game timing. This can be rewound for /// prediction, and is affected by Paused and TimeScale. /// TimeSpan CurTime { get; } /// /// The current real uptime of the simulation. Use this for UI and out of game timing, it is not affected /// by pausing, timescale, or lag. /// TimeSpan RealTime { get; } /// /// The time (on the scale) when the current frame started. /// TimeSpan FrameStartTime { get; } /// /// The of the server. /// /// /// 0 if we are the client and we are not connected to a server. /// if we are the server. /// TimeSpan ServerTime { get; } /// /// The simulated time it took to render the last frame. /// TimeSpan FrameTime { get; } /// /// The real time it took to render the last frame. /// TimeSpan RealFrameTime { get; } /// /// Average real frame time over the last 50 frames. /// TimeSpan RealFrameTimeAvg { get; } /// /// Standard Deviation of the frame time over the last 50 frames. /// TimeSpan RealFrameTimeStdDev { get; } /// /// Current graphics frame since init OpenGL which is taken as frame 1. Useful to set a conditional breakpoint on specific frames, and /// synchronize with OGL debugging tools that capture frames. Depending on the tools used, this frame /// number will vary between 1 frame more or less due to how that tool is counting frames, /// i.e. starting from 0 or 1, having a separate counter, etc. Available in timing debug panel. /// uint CurFrame { get; set; } /// /// Average real FPS over the last 50 frames. /// double FramesPerSecondAvg { get; } /// /// The current simulation tick being processed. /// GameTick CurTick { get; set; } /// /// Time, relative to , the last tick started at. /// If we're currently in simulation, that's THIS tick. /// TimeSpan LastTick { get; set; } /// /// The target ticks/second of the simulation. /// /// /// This is specified in simulation time, not real time. /// ushort TickRate { get; set; } /// /// The scale of simulation time to real time. /// /// /// A scale of 2 means the game should go "twice as slow" /// float TimeScale { get; set; } /// /// The baseline time value that CurTime is calculated relatively to. /// (TimeSpan, GameTick) TimeBase { get; set; } /// /// The length of a tick at the current TickRate. 1/TickRate. /// /// /// This is in simulation time, not necessarily real time. /// TimeSpan TickPeriod { get; } /// /// The remaining time left over after the last tick was ran. /// TimeSpan TickRemainder { get; set; } /// /// in real time. /// TimeSpan TickRemainderRealtime { get; } /// /// Calculate the amount of real time to wait between ticks. /// /// /// This is adjusted for various "out of simulation" /// factors such as and . /// TimeSpan CalcAdjustedTickPeriod(); /// /// Fraction of how far into the tick we are. 0 is 0% and is 100%. /// ushort TickFraction { get { if (InSimulation) { return ushort.MaxValue; } return (ushort)(ushort.MaxValue * TickRemainder.TotalSeconds / TickPeriod.TotalSeconds); } } /// /// If the client clock is a little behind or ahead of the server, you can /// use the to adjust the timing of the clock speed. The default value is 0, /// and you can run the clock from -1 (almost stopped) to 1 (almost no delay). /// This has no effect on in-simulation timing, and only changes the speed at which /// the simulation progresses in relation to Real time. Don't mess with this unless /// you know what you are doing. DO NOT TOUCH THIS ON SERVER. /// float TickTimingAdjustment { get; set; } /// /// Ends the 'lap' of the timer, updating frame time info. /// void StartFrame(); /// /// Is this the first time CurTick has been predicted? /// bool IsFirstTimePredicted { get; } /// /// True if CurTick is ahead of LastRealTick, and is false. /// /// /// This means the client is currently running ahead of the server, to fill in the gaps for the player and /// reduce latency while waiting for the next game state to arrive. /// bool InPrediction { get; } /// /// If true, the game is currently in the process of applying a game server-state. /// bool ApplyingState { get; } string TickStamp => $"{CurTick}, predFirst: {IsFirstTimePredicted}, tickRem: {TickRemainder.TotalSeconds}, sim: {InSimulation}"; /// /// Statically-accessible version of . /// /// /// This is intended as a debugging aid, and should not be used in regular committed code. /// static string TickStampStatic => IoCManager.Resolve().TickStamp; /// /// Resets the simulation time completely. While functional, no mainstream RobustToolbox game currently uses /// this outside of client synchronization with the server and it may have quirks on existing titles. /// /// /// To avoid potential desynchronization where some entities think they have changes from the far future, /// this should be accompanied by a full ECS reset using . /// void ResetSimTime(); /// void ResetSimTime((TimeSpan, GameTick) timeBase); void SetTickRateAt(ushort tickRate, GameTick atTick); TimeSpan RealLocalToServer(TimeSpan local); TimeSpan RealServerToLocal(TimeSpan server); } }