using System; using System.Collections.Generic; using System.Diagnostics; namespace Coroutine { /// /// A reference to a currently running coroutine. /// This is returned by . /// public class ActiveCoroutine : IComparable { private readonly IEnumerator enumerator; private readonly Stopwatch stopwatch; private Wait current; /// /// This property stores whether or not this active coroutine is finished. /// A coroutine is finished if all of its waits have passed, or if it . /// public bool IsFinished { get; private set; } /// /// This property stores whether or not this active coroutine was cancelled using . /// public bool WasCanceled { get; private set; } /// /// The total amount of time that took. /// This is the amount of time that this active coroutine took for the entirety of its "steps", or yield statements. /// public TimeSpan TotalMoveNextTime { get; private set; } /// /// The total amount of times that was invoked. /// This is the amount of "steps" in your coroutine, or the amount of yield statements. /// public int MoveNextCount { get; private set; } /// /// The maximum amount of time that took. /// This is the maximum amount of time that each "step", or each yield statement, of this coroutine took to execute. /// public TimeSpan MaxMoveNextTime { get; private set; } /// /// The average amount of time that took. /// This is the average amount of time that each "step", or each yield statement, of this coroutine took to execute. /// public TimeSpan AverageMoveNextTime => new TimeSpan(this.TotalMoveNextTime.Ticks / this.MoveNextCount); /// /// An event that gets fired when this active coroutine finishes or gets cancelled. /// When this event is called, is always true. /// public event FinishCallback OnFinished; /// /// The name of this coroutine. /// When not specified on startup of this coroutine, the name defaults to an empty string. /// public readonly string Name; /// /// The priority of this coroutine. The higher the priority, the earlier it is advanced compared to other coroutines that advance around the same time. /// When not specified at startup of this coroutine, the priority defaults to 0. /// public readonly int Priority; internal ActiveCoroutine(IEnumerator enumerator, string name, int priority, Stopwatch stopwatch) { this.enumerator = enumerator; this.Name = name; this.Priority = priority; this.stopwatch = stopwatch; } /// /// Cancels this coroutine, causing all subsequent s and any code in between to be skipped. /// /// Whether the cancellation was successful, or this coroutine was already cancelled or finished public bool Cancel() { if (this.IsFinished || this.WasCanceled) return false; this.WasCanceled = true; this.IsFinished = true; this.OnFinished?.Invoke(this); return true; } internal bool Tick(double deltaSeconds) { if (!this.WasCanceled) { if (this.current.Tick(deltaSeconds)) this.MoveNext(); } return this.IsFinished; } internal bool OnEvent(Event evt) { if (!this.WasCanceled) { if (this.current.OnEvent(evt)) this.MoveNext(); } return this.IsFinished; } internal bool MoveNext() { this.stopwatch.Restart(); var result = this.enumerator.MoveNext(); this.stopwatch.Stop(); this.TotalMoveNextTime += this.stopwatch.Elapsed; if (this.stopwatch.Elapsed > this.MaxMoveNextTime) this.MaxMoveNextTime = this.stopwatch.Elapsed; this.MoveNextCount++; if (!result) { this.IsFinished = true; this.OnFinished?.Invoke(this); return false; } this.current = this.enumerator.Current; return true; } internal bool IsWaitingForEvent() { return this.current.IsWaitingForEvent(); } /// /// A delegate method used by . /// /// The coroutine that finished public delegate void FinishCallback(ActiveCoroutine coroutine); /// public int CompareTo(ActiveCoroutine other) { return other.Priority.CompareTo(this.Priority); } } }