using System; using System.Collections; using System.Collections.Generic; using System.Threading.Tasks; namespace JNGame.Runtime.Util { /// Author: Pim de Witte (pimdewitte.com) and contributors, https://github.com/PimDeWitte/UnityMainThreadDispatcher /// /// A thread-safe class which holds a queue with actions to execute on the next Update() method. It can be used to make calls to the main thread for /// things such as UI Manipulation in Unity. It was developed for use in combination with the Firebase Unity plugin, which uses separate threads for event handling /// public class UnityMainThreadDispatcher : SingletonScene { private readonly Queue _executionQueue = new Queue(); public void Update() { lock(_executionQueue) { while (_executionQueue.Count > 0) { _executionQueue.Dequeue().Invoke(); } } } /// /// Locks the queue and adds the IEnumerator to the queue /// /// IEnumerator function that will be executed from the main thread. public void Enqueue(IEnumerator action) { lock (_executionQueue) { _executionQueue.Enqueue (() => { StartCoroutine(action); }); } } /// /// Locks the queue and adds the Action to the queue /// /// function that will be executed from the main thread. public void Enqueue(Action action) { Enqueue(ActionWrapper(action)); } /// /// Locks the queue and adds the Action to the queue, returning a Task which is completed when the action completes /// /// function that will be executed from the main thread. /// A Task that can be awaited until the action completes public Task EnqueueAsync(Action action) { var tcs = new TaskCompletionSource(); void WrappedAction() { try { action(); tcs.TrySetResult(true); } catch (Exception ex) { tcs.TrySetException(ex); } } Enqueue(ActionWrapper(WrappedAction)); return tcs.Task; } IEnumerator ActionWrapper(Action a) { a(); yield return null; } } }