diff --git a/TaskManager.cs b/TaskManager.cs
index 7822ca0..72d28fe 100644
--- a/TaskManager.cs
+++ b/TaskManager.cs
@@ -1,191 +1,259 @@
-/// TaskManager.cs
-///
-/// This is a convenient coroutine API for Unity.
-///
-/// Example usage:
-/// IEnumerator MyAwesomeTask()
-/// {
-/// while(true) {
-/// // ...
-/// yield return null;
-//// }
-/// }
-///
-/// IEnumerator TaskKiller(float delay, Task t)
-/// {
-/// yield return new WaitForSeconds(delay);
-/// t.Stop();
-/// }
-///
-/// // From anywhere
-/// Task my_task = new Task(MyAwesomeTask());
-/// new Task(TaskKiller(5, my_task));
-///
-/// The code above will schedule MyAwesomeTask() and keep it running
-/// concurrently until either it terminates on its own, or 5 seconds elapses
-/// and triggers the TaskKiller Task that was created.
-///
-/// Note that to facilitate this API's behavior, a "TaskManager" GameObject is
-/// created lazily on first use of the Task API and placed in the scene root
-/// with the internal TaskManager component attached. All coroutine dispatch
-/// for Tasks is done through this component.
-
-using UnityEngine;
using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+
+///
+/// Addendum to krockot's original task manager
+/// Add possibility to pool a bunch of tasks together, so they can be started, stopped,... together
+///
+public class TaskPool {
+ public delegate void AllFinishedHandler();
+
+ private readonly List tasks = new();
+ private int finishedTaskCounter;
+
+ public bool AllRunning => CheckIfAllAreRunning();
+ public bool AllPaused => CheckIfAllArePaused();
+ private bool PoolLocked { get; set; }
+ private bool finished = false;
+
+ ///
+ /// Gets triggered when all tasks finished.
+ ///
+ public event AllFinishedHandler AllFinished;
+
+ ///
+ /// Add a task to the pool
+ ///
+ /// The task, that should be added to the pool
+ ///
+ /// Indicates if a task could be added successfully to the pool.
+ /// If pool is already running, it gets locked and no further task can be added.
+ ///
+ public bool Add(PoolTask _task) {
+ if (PoolLocked) {
+ return false;
+ }
+
+ tasks.Add(_task);
+ _task.Finished += ATaskFinished;
+ return true;
+ }
+
+ ///
+ /// Start all tasks within the pool together
+ ///
+ public void StartAll() {
+ PoolLocked = true;
+ foreach (Task task in tasks) {
+ task.Start();
+ }
+ }
+
+ ///
+ /// Stop all the tasks within the pool together
+ ///
+ public void StopAll() {
+ foreach (Task task in tasks) {
+ task.Stop();
+ }
+ }
+
+ ///
+ /// Pause all the tasks in the pool
+ ///
+ public void PauseAll() {
+ foreach (Task task in tasks) {
+ task.Pause();
+ }
+ }
+ ///
+ /// Resume all the tasks that are paused in the pool
+ ///
+ public void UnpauseAll() {
+ foreach (Task task in tasks) {
+ task.Unpause();
+ }
+ }
+
+ private bool CheckIfAllAreRunning() {
+ bool allRunning = true;
+ foreach (Task unused in tasks.Where(_task => !_task.Running)) {
+ allRunning = false;
+ }
+
+ return allRunning;
+ }
+
+ private bool CheckIfAllArePaused() {
+ bool allPaused = true;
+ foreach (Task unused in tasks.Where(_task => !_task.Paused)) {
+ allPaused = false;
+ }
+
+ return allPaused;
+ }
+
+ private void ATaskFinished(bool _manual) {
+ finishedTaskCounter++;
+ if (!finished && finishedTaskCounter == tasks.Count) {
+ finished = true;
+ AllFinishedHandler handler = AllFinished;
+ handler?.Invoke();
+ }
+ }
+}
+
+///
/// A Task object represents a coroutine. Tasks can be started, paused, and stopped.
-/// It is an error to attempt to start a task that has been stopped or which has
-/// naturally terminated.
-public class Task
-{
- /// Returns true if and only if the coroutine is running. Paused tasks
- /// are considered to be running.
- public bool Running {
- get {
- return task.Running;
- }
- }
-
- /// Returns true if and only if the coroutine is currently paused.
- public bool Paused {
- get {
- return task.Paused;
- }
- }
-
- /// Delegate for termination subscribers. manual is true if and only if
- /// the coroutine was stopped with an explicit call to Stop().
- public delegate void FinishedHandler(bool manual);
-
- /// Termination event. Triggered when the coroutine completes execution.
- public event FinishedHandler Finished;
-
- /// Creates a new Task object for the given coroutine.
- ///
- /// If autoStart is true (default) the task is automatically started
- /// upon construction.
- public Task(IEnumerator c, bool autoStart = true)
- {
- task = TaskManager.CreateTask(c);
- task.Finished += TaskFinished;
- if(autoStart)
- Start();
- }
-
- /// Begins execution of the coroutine
- public void Start()
- {
- task.Start();
- }
-
- /// Discontinues execution of the coroutine at its next yield.
- public void Stop()
- {
- task.Stop();
- }
-
- public void Pause()
- {
- task.Pause();
- }
-
- public void Unpause()
- {
- task.Unpause();
- }
-
- void TaskFinished(bool manual)
- {
- FinishedHandler handler = Finished;
- if(handler != null)
- handler(manual);
- }
-
- TaskManager.TaskState task;
+/// It is an error to attempt to start a task that has been stopped or which has naturally terminated.
+///
+public class Task {
+
+ ///
+ /// Delegate for termination subscribers. Manual is true if and only if
+ /// the coroutine was stopped with an explicit call to Stop().
+ ///
+ public delegate void FinishedHandler(bool _manual);
+
+ private readonly TaskManager.TaskState task;
+
+ ///
+
+ ///
+
+
+ ///
+ /// Creates a new Task object for the given coroutine.
+ /// If autoStart is true (default) the task is automatically started upon construction.
+ ///
+ public Task(IEnumerator _task, bool _autoStart = true) {
+ task = TaskManager.CreateTask(_task);
+ task.Finished += TaskFinished;
+ if (_autoStart) {
+ Start();
+ }
+ }
+
+
+ ///
+ /// Returns true if and only if the coroutine is running. Paused tasks are considered to be running.
+ ///
+ public bool Running => task.Running;
+
+ ///
+ /// Returns true if and only if the coroutine is currently paused.
+ ///
+ public bool Paused => task.Paused;
+
+ ///
+ /// Termination event. Triggered when the coroutine completes execution.
+ ///
+ public event FinishedHandler Finished;
+
+ ///
+ /// Begins execution of the coroutine
+ ///
+ public void Start() {
+ task.Start();
+ }
+
+ ///
+ /// Discontinues execution of the coroutine at its next yield.
+ ///
+ public void Stop() {
+ task.Stop();
+ }
+
+ public void Pause() {
+ task.Pause();
+ }
+
+ public void Unpause() {
+ task.Unpause();
+ }
+
+ private void TaskFinished(bool _manual) {
+ FinishedHandler handler = Finished;
+ handler?.Invoke(_manual);
+ }
}
-class TaskManager : MonoBehaviour
-{
- public class TaskState
- {
- public bool Running {
- get {
- return running;
- }
- }
-
- public bool Paused {
- get {
- return paused;
- }
- }
-
- public delegate void FinishedHandler(bool manual);
- public event FinishedHandler Finished;
-
- IEnumerator coroutine;
- bool running;
- bool paused;
- bool stopped;
-
- public TaskState(IEnumerator c)
- {
- coroutine = c;
- }
-
- public void Pause()
- {
- paused = true;
- }
-
- public void Unpause()
- {
- paused = false;
- }
-
- public void Start()
- {
- running = true;
- singleton.StartCoroutine(CallWrapper());
- }
-
- public void Stop()
- {
- stopped = true;
- running = false;
- }
-
- IEnumerator CallWrapper()
- {
- yield return null;
- IEnumerator e = coroutine;
- while(running) {
- if(paused)
- yield return null;
- else {
- if(e != null && e.MoveNext()) {
- yield return e.Current;
- }
- else {
- running = false;
- }
- }
- }
-
- FinishedHandler handler = Finished;
- if(handler != null)
- handler(stopped);
- }
- }
-
- static TaskManager singleton;
-
- public static TaskState CreateTask(IEnumerator coroutine)
- {
- if(singleton == null) {
- GameObject go = new GameObject("TaskManager");
- singleton = go.AddComponent();
- }
- return new TaskState(coroutine);
- }
+///
+/// Specialized task for pool, with no auto start
+/// This way, all tasks within the pool can be started together
+///
+public class PoolTask : Task {
+ public PoolTask(IEnumerator _task) : base(_task, false) { }
}
+
+internal class TaskManager : MonoBehaviour {
+ private static TaskManager instance;
+
+ public static TaskState CreateTask(IEnumerator _coroutine) {
+ if (instance != null) {
+ return new TaskState(_coroutine);
+ }
+
+ GameObject go = new("TaskManager");
+ instance = go.AddComponent();
+
+ return new TaskState(_coroutine);
+ }
+
+ public class TaskState {
+ public delegate void FinishedHandler(bool _manual);
+
+ private readonly IEnumerator coroutine;
+ private bool stopped;
+
+ public TaskState(IEnumerator _task) {
+ coroutine = _task;
+ }
+
+ public bool Running { get; private set; }
+
+ public bool Paused { get; private set; }
+
+ public event FinishedHandler Finished;
+
+ public void Pause() {
+ Paused = true;
+ }
+
+ public void Unpause() {
+ Paused = false;
+ }
+
+ public void Start() {
+ Running = true;
+ instance.StartCoroutine(CallWrapper());
+ }
+
+ public void Stop() {
+ stopped = true;
+ Running = false;
+ }
+
+ private IEnumerator CallWrapper() {
+ yield return null;
+ IEnumerator e = coroutine;
+ while (Running) {
+ if (Paused) {
+ yield return null;
+ } else {
+ if (e != null && e.MoveNext()) {
+ yield return e.Current;
+ } else {
+ Running = false;
+ }
+ }
+ }
+
+ FinishedHandler handler = Finished;
+ handler?.Invoke(stopped);
+ }
+ }
+}
\ No newline at end of file