using System; using System.Threading; using System.Threading.Tasks; using Robust.Shared.Exceptions; using Robust.Shared.IoC; namespace Robust.Shared.Timing { /// /// Non-serializable, but async friendly timers. /// /// /// Using these in Space Station 14 is discouraged, it has its own idioms that are all serialization friendly. /// /// public sealed class Timer { /// /// Counts the time (in milliseconds) before firing again. /// private float _timeCounter; /// /// Time (in milliseconds) between firings. /// public int Time { get; } /// /// Whether or not this timer should repeat. /// public bool IsRepeating { get; } /// /// Whether or not this timer is still running. /// public bool IsActive { get; private set; } = true; /// /// Called when the timer is fired. /// public Action OnFired { get; } public Timer(int milliseconds, bool isRepeating, Action onFired) { _timeCounter = Time = milliseconds; IsRepeating = isRepeating; OnFired = onFired; } // Parameter is used only on release. // ReSharper disable once UnusedParameter.Global public void Update(float frameTime, IRuntimeLog runtimeLog) { if (IsActive) { _timeCounter -= frameTime * 1000; if (_timeCounter <= 0) { #if EXCEPTION_TOLERANCE try #endif { OnFired(); } #if EXCEPTION_TOLERANCE catch (Exception e) { runtimeLog.LogException(e, "Timer Callback"); } #endif if (IsRepeating) { _timeCounter += Time; } else { IsActive = false; } } } } /// /// Creates a task that will complete after a given delay. /// The task is resumed on the main game logic thread. /// /// The length of time, in milliseconds, to delay for. /// /// The task that can be awaited. public static Task Delay(int milliseconds, CancellationToken cancellationToken = default) { var tcs = new TaskCompletionSource(); Spawn(milliseconds, () => tcs.SetResult(null), cancellationToken); return tcs.Task; } /// /// Creates a task that will complete after a given delay. /// The task is resumed on the main game logic thread. /// /// The length of time to delay for. /// /// The task that can be awaited. public static Task Delay(TimeSpan duration, CancellationToken cancellationToken = default) { return Delay((int)duration.TotalMilliseconds, cancellationToken); } /// /// Schedule an action to be fired after a certain delay. /// The action will be resumed on the main game logic thread. /// /// The length of time, in milliseconds, to wait before firing the action. /// The action to fire. /// public static void Spawn(int milliseconds, Action onFired, CancellationToken cancellationToken = default) { var timer = new Timer(milliseconds, false, onFired); IoCManager.Resolve().AddTimer(timer, cancellationToken); } /// /// Schedule an action to be fired after a certain delay. /// The action will be resumed on the main game logic thread. /// /// The length of time, to wait before firing the action. /// The action to fire. /// public static void Spawn(TimeSpan duration, Action onFired, CancellationToken cancellationToken = default) { Spawn((int)duration.TotalMilliseconds, onFired, cancellationToken); } /// /// Schedule an action that repeatedly fires after a delay specified in milliseconds. /// /// The length of time, in milliseconds, to delay before firing the repeated action. /// The action to fire. /// The CancellationToken for stopping the Timer. public static void SpawnRepeating(int milliseconds, Action onFired, CancellationToken cancellationToken) { var timer = new Timer(milliseconds, true, onFired); IoCManager.Resolve().AddTimer(timer, cancellationToken); } /// /// Schedule an action that repeatedly fires after a delay. /// /// The length of time to delay before firing the repeated action. /// The action to fire. /// The CancellationToken for stopping the Timer. public static void SpawnRepeating(TimeSpan duration, Action onFired, CancellationToken cancellationToken) { SpawnRepeating((int)duration.TotalMilliseconds, onFired, cancellationToken); } } }