// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik // using System; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Text; namespace Animancer { /// A very simple timer system based on a . public struct SimpleTimer : IDisposable { /************************************************************************************************************************/ /// The default contains 3 decimal places. const string Format3DP = "0.000"; /// A default timer that hasn't been started. public static SimpleTimer Default = new(null); /************************************************************************************************************************/ /// The system used to track time. public static readonly Stopwatch Stopwatch = Stopwatch.StartNew(); /************************************************************************************************************************/ /// An optional prefix for . public string name; /// The string format to use for . /// /// If null, ticks will be used directly. /// Otherwise, the ticks will be converted to seconds and this format will be used. /// public string format; /// The from when this timer was started. /// If not started, this value will be -1. public long startTicks; /// The total number of ticks that have elapsed since the . /// This value is updated by . public long totalTicks; /************************************************************************************************************************/ /// Converts the to seconds. public readonly double StartTimeSeconds => startTicks / (double)Stopwatch.Frequency; /// Converts the to seconds. public readonly double TotalTimeSeconds => totalTicks / (double)Stopwatch.Frequency; /************************************************************************************************************************/ /// Has been called and not? public readonly bool IsStarted => startTicks != -1; /************************************************************************************************************************/ /// Creates a new with the specified `name`. /// /// You will need to call to start the timer. /// Or use the static . /// /// Use null as the `format` to have return the ticks instead of seconds. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public SimpleTimer(string name, string format = Format3DP) { this.name = name; this.format = format; startTicks = -1; totalTicks = 0; } /************************************************************************************************************************/ /// Creates a new with the specified `name` and starts it. /// Use null as the `format` to have return the ticks instead of seconds. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static SimpleTimer Start(string name = null, string format = Format3DP) => new() { name = name, format = format, startTicks = Stopwatch.ElapsedTicks, }; /************************************************************************************************************************/ /// /// Stores the in /// so that will be able to calculate how much time has passed. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Start() => startTicks = Stopwatch.ElapsedTicks; /// Clears the . [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Cancel() => startTicks = -1; /************************************************************************************************************************/ /// /// Calculates the amount of time that has passed since the /// and returns it after adding it to the . /// Also resumes this timer. /// /// Returns -1 if this timer wasn't started. [MethodImpl(MethodImplOptions.AggressiveInlining)] public long Count() { var endTicks = Stopwatch.ElapsedTicks; long count; if (startTicks >= 0) { count = endTicks - startTicks; totalTicks += count; } else { count = -1; } startTicks = endTicks; return count; } /************************************************************************************************************************/ private static StringBuilder _StringBuilder; /// Calls and returns a string describing the current values of this timer. public override string ToString() { var count = Count(); if (_StringBuilder == null) _StringBuilder = new(); else _StringBuilder.Length = 0; if (!string.IsNullOrEmpty(name)) _StringBuilder.Append(name) .Append(": "); if (count != totalTicks && count >= 0) { _StringBuilder .Append("Count ") .Append(Format(count)) .Append(", Total "); } _StringBuilder.Append(Format(totalTicks)); return _StringBuilder.ToString(); } /************************************************************************************************************************/ /// Converts the given `ticks` to a string using the . public readonly string Format(long ticks) => format is null ? $"{ticks} Ticks" : $"{(ticks / (double)Stopwatch.Frequency).ToString(format)}s"; /************************************************************************************************************************/ /// Logs and calls . public void Dispose() { UnityEngine.Debug.Log(ToString()); Cancel(); totalTicks = 0; } /************************************************************************************************************************/ } }