diff --git a/Coroutine/ActiveCoroutine.cs b/Coroutine/ActiveCoroutine.cs index e6067c8..ef33d41 100644 --- a/Coroutine/ActiveCoroutine.cs +++ b/Coroutine/ActiveCoroutine.cs @@ -7,7 +7,7 @@ namespace Coroutine { /// A reference to a currently running coroutine. /// This is returned by . /// - public class ActiveCoroutine { + public class ActiveCoroutine : IComparable { private readonly IEnumerator enumerator; private readonly Stopwatch stopwatch; @@ -52,11 +52,17 @@ namespace 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, Stopwatch stopwatch) { + internal ActiveCoroutine(IEnumerator enumerator, string name, int priority, Stopwatch stopwatch) { this.enumerator = enumerator; - this.stopwatch = stopwatch; this.Name = name; + this.Priority = priority; + this.stopwatch = stopwatch; } /// @@ -93,8 +99,7 @@ namespace Coroutine { var result = this.enumerator.MoveNext(); this.stopwatch.Stop(); this.TotalMoveNextTime += this.stopwatch.Elapsed; - if (this.stopwatch.Elapsed > this.MaxMoveNextTime) - { + if (this.stopwatch.Elapsed > this.MaxMoveNextTime) { this.MaxMoveNextTime = this.stopwatch.Elapsed; } this.MoveNextCount++; @@ -118,5 +123,10 @@ namespace Coroutine { /// The coroutine that finished public delegate void FinishCallback(ActiveCoroutine coroutine); + /// + public int CompareTo(ActiveCoroutine other) { + return other.Priority.CompareTo(this.Priority); + } + } } \ No newline at end of file diff --git a/Coroutine/CoroutineHandler.cs b/Coroutine/CoroutineHandler.cs index cd3238b..a5673f1 100644 --- a/Coroutine/CoroutineHandler.cs +++ b/Coroutine/CoroutineHandler.cs @@ -15,19 +15,19 @@ namespace Coroutine { /// public static int EventCount => Instance.EventCount; - /// - public static ActiveCoroutine Start(IEnumerable coroutine, string name = "") { - return Instance.Start(coroutine, name); + /// + public static ActiveCoroutine Start(IEnumerable coroutine, string name = "", int priority = 0) { + return Instance.Start(coroutine, name, priority); } - /// - public static ActiveCoroutine Start(IEnumerator coroutine, string name = "") { - return Instance.Start(coroutine, name); + /// + public static ActiveCoroutine Start(IEnumerator coroutine, string name = "", int priority = 0) { + return Instance.Start(coroutine, name, priority); } /// - public static ActiveCoroutine InvokeLater(Wait wait, Action action) { - return Instance.InvokeLater(wait, action); + public static ActiveCoroutine InvokeLater(Wait wait, Action action, string name = "", int priority = 0) { + return Instance.InvokeLater(wait, action, name, priority); } /// diff --git a/Coroutine/CoroutineHandlerInstance.cs b/Coroutine/CoroutineHandlerInstance.cs index 35fc62f..8b8fe46 100644 --- a/Coroutine/CoroutineHandlerInstance.cs +++ b/Coroutine/CoroutineHandlerInstance.cs @@ -28,27 +28,24 @@ namespace Coroutine { /// Note that this calls to get the enumerator. /// /// The coroutine to start - /// The name that this coroutine should have. Defaults to an empty string. + /// The that this coroutine should have. Defaults to an empty string. + /// The that this coroutine should have. The higher the priority, the earlier it is advanced. Defaults to 0. /// An active coroutine object representing this coroutine - public ActiveCoroutine Start(IEnumerable coroutine, string name = "") { - return this.Start(coroutine.GetEnumerator(), name); + public ActiveCoroutine Start(IEnumerable coroutine, string name = "", int priority = 0) { + return this.Start(coroutine.GetEnumerator(), name, priority); } /// /// Starts the given coroutine, returning a object for management. /// /// The coroutine to start - /// The name that this coroutine should have. Defaults to an empty string. + /// The that this coroutine should have. Defaults to an empty string. + /// The that this coroutine should have. The higher the priority, the earlier it is advanced compared to other coroutines that advance around the same time. Defaults to 0. /// An active coroutine object representing this coroutine - public ActiveCoroutine Start(IEnumerator coroutine, string name = "") { - var inst = new ActiveCoroutine(coroutine, name, this.stopwatch); - if (inst.MoveNext()) { - if (inst.IsWaitingForEvent()) { - this.eventCoroutines.Add(inst); - } else { - this.tickingCoroutines.Add(inst); - } - } + public ActiveCoroutine Start(IEnumerator coroutine, string name = "", int priority = 0) { + var inst = new ActiveCoroutine(coroutine, name, priority, this.stopwatch); + if (inst.MoveNext()) + AddSorted(inst.IsWaitingForEvent() ? this.eventCoroutines : this.tickingCoroutines, inst); return inst; } @@ -58,9 +55,11 @@ namespace Coroutine { /// /// The wait to wait for /// The action to execute after waiting + /// The that the underlying coroutine should have. Defaults to an empty string. + /// The that the underlying coroutine should have. The higher the priority, the earlier it is advanced compared to other coroutines that advance around the same time. Defaults to 0. /// An active coroutine object representing this coroutine - public ActiveCoroutine InvokeLater(Wait wait, Action action) { - return this.Start(InvokeLaterImpl(wait, action)); + public ActiveCoroutine InvokeLater(Wait wait, Action action, string name = "", int priority = 0) { + return this.Start(InvokeLaterImpl(wait, action), name, priority); } /// @@ -68,15 +67,15 @@ namespace Coroutine { /// /// The amount of seconds that have passed since the last time this method was invoked public void Tick(double deltaSeconds) { - for (var i = this.tickingCoroutines.Count - 1; i >= 0; i--) { - var coroutine = this.tickingCoroutines[i]; - if (coroutine.Tick(deltaSeconds)) { - this.tickingCoroutines.RemoveAt(i); - } else if (coroutine.IsWaitingForEvent()) { - this.tickingCoroutines.RemoveAt(i); - this.eventCoroutines.Add(coroutine); + this.tickingCoroutines.RemoveAll(c => { + if (c.Tick(deltaSeconds)) { + return true; + } else if (c.IsWaitingForEvent()) { + AddSorted(this.eventCoroutines, c); + return true; } - } + return false; + }); } /// @@ -84,15 +83,15 @@ namespace Coroutine { /// /// The event to raise public void RaiseEvent(Event evt) { - for (var i = this.eventCoroutines.Count - 1; i >= 0; i--) { - var coroutine = this.eventCoroutines[i]; - if (coroutine.OnEvent(evt)) { - this.eventCoroutines.RemoveAt(i); - } else if (!coroutine.IsWaitingForEvent()) { - this.eventCoroutines.RemoveAt(i); - this.tickingCoroutines.Add(coroutine); + this.eventCoroutines.RemoveAll(c => { + if (c.OnEvent(evt)) { + return true; + } else if (!c.IsWaitingForEvent()) { + AddSorted(this.tickingCoroutines, c); + return true; } - } + return false; + }); } /// @@ -108,5 +107,10 @@ namespace Coroutine { action(); } + private static void AddSorted(List list, ActiveCoroutine coroutine) { + var position = list.BinarySearch(coroutine); + list.Insert(position < 0 ? ~position : position, coroutine); + } + } } \ No newline at end of file diff --git a/Test/Example.cs b/Test/Example.cs index 380d908..cd774f0 100644 --- a/Test/Example.cs +++ b/Test/Example.cs @@ -20,6 +20,9 @@ namespace Test { }); CoroutineHandler.InvokeLater(new Wait(TestEvent), () => Console.WriteLine("Test event received")); + CoroutineHandler.InvokeLater(new Wait(TestEvent), () => Console.WriteLine("I am invoked after 'Test event received'"), priority: -5); + CoroutineHandler.InvokeLater(new Wait(TestEvent), () => Console.WriteLine("I am invoked before 'Test event received'"), priority: 2); + var lastTime = DateTime.Now; while (true) { var currTime = DateTime.Now; @@ -51,9 +54,9 @@ namespace Test { if (first.IsFinished) { Console.WriteLine("By the way, the first coroutine has finished!"); Console.WriteLine($"{first.Name} data: {first.MoveNextCount} moves, " + - $"{first.TotalMoveNextTime.TotalMilliseconds} total time, " + - $"{first.AverageMoveNextTime.TotalMilliseconds} average, " + - $"{first.MaxMoveNextTime.TotalMilliseconds} maximum"); + $"{first.TotalMoveNextTime.TotalMilliseconds} total time, " + + $"{first.AverageMoveNextTime.TotalMilliseconds} average, " + + $"{first.MaxMoveNextTime.TotalMilliseconds} maximum"); Environment.Exit(0); } }