diff --git a/Engine.Core/Systems/Abstract/ICoroutineManager.cs b/Engine.Core/Systems/Abstract/ICoroutineManager.cs new file mode 100644 index 0000000..7d2592a --- /dev/null +++ b/Engine.Core/Systems/Abstract/ICoroutineManager.cs @@ -0,0 +1,9 @@ +using System.Collections; + +namespace Engine.Core; + +public interface ICoroutineManager +{ + IEnumerator StartCoroutine(IEnumerator enumerator); + void StopCoroutine(IEnumerator enumerator); +} diff --git a/Engine.Core/Systems/NestedCoroutineManager.cs b/Engine.Core/Systems/NestedCoroutineManager.cs new file mode 100644 index 0000000..e53bad2 --- /dev/null +++ b/Engine.Core/Systems/NestedCoroutineManager.cs @@ -0,0 +1,80 @@ +using System.Collections; +using System.Collections.Generic; + +namespace Engine.Core; + +public class NestedCoroutineManager : Behaviour, IUpdate, ICoroutineManager +{ + private readonly List stacks = []; + private readonly Pool pool = new(() => new()); + + public IEnumerator StartCoroutine(IEnumerator enumerator) + { + CoroutineStack stack = pool.Get(); + stack.EntryPoint = enumerator; + stack.Stack.Push(enumerator); + + stacks.Add(stack); + + return enumerator; + } + + public void StopCoroutine(IEnumerator enumerator) + { + for (int i = 0; i < stacks.Count; i++) + if (stacks[i].EntryPoint == enumerator) + { + RemoveCoroutineAt(i); + return; + } + } + + private void RemoveCoroutineAt(int i) + { + stacks[i].Reset(); + stacks.RemoveAt(i); + } + + void IUpdate.Update() + { + for (int i = stacks.Count - 1; i >= 0; i--) + { + Stack stack = stacks[i].Stack; + + if (stack.Count == 0) + { + RemoveCoroutineAt(i); + continue; + } + + IEnumerator top = stack.Peek(); + + if (top.Current is ICoroutineYield coroutineYield && coroutineYield.Yield()) + continue; + + if (top.Current is IEnumerator nested) + { + stack.Push(nested); + continue; + } + + if (!top.MoveNext()) + { + stack.Pop(); + if (stack.Count != 0) + stack.Peek().MoveNext(); + continue; + } + } + } + + private class CoroutineStack + { + public IEnumerator EntryPoint = null!; + public Stack Stack = new(); + + public void Reset() { EntryPoint = null!; Stack.Clear(); } + } + + public NestedCoroutineManager() => Priority = int.MinValue; +} diff --git a/Engine.Systems/Tween/TweenManager.cs b/Engine.Systems/Tween/TweenManager.cs index 7a6793e..0921f5d 100644 --- a/Engine.Systems/Tween/TweenManager.cs +++ b/Engine.Systems/Tween/TweenManager.cs @@ -7,7 +7,7 @@ namespace Engine.Systems.Tween; public class TweenManager : Behaviour, IEnterUniverse, IExitUniverse, ITweenManager { - private CoroutineManager coroutineManager = null!; + private ICoroutineManager coroutineManager = null!; private readonly Dictionary runningCoroutines = []; private readonly Queue pool = new(); @@ -75,7 +75,7 @@ public class TweenManager : Behaviour, IEnterUniverse, IExitUniverse, ITweenMana public void EnterUniverse(IUniverse universe) { - coroutineManager = universe.FindRequiredBehaviour(); + coroutineManager = universe.FindRequiredBehaviour(); } public void ExitUniverse(IUniverse universe)