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;
}
}
}