using System; using System.Threading; using System.Threading.Tasks; using Chartboost.Logging; using UnityEditor; using UnityEngine; namespace Chartboost { /// /// Utility class to dispatch functionality into Unity's main thread. /// If your code contains references to any Unity Code and not just raw C#, you will have to dispatch it to the Unity main thread. /// public static class MainThreadDispatcher { /// /// Synchronous; blocks until the callback completes /// public static void Send(SendOrPostCallback callback) => _context.Send(callback, null); /// /// Asynchronous; send and forget /// public static void Post(SendOrPostCallback callback) => _context.Post(callback, null); /// /// Creates and dispatches a to run on the Unity Scheduler. /// /// The to be executed on the Unity Scheduler. /// /// A that represents the asynchronous operation. This /// will log any exceptions that occur during its execution using the Unity logging system. /// public static Task MainThreadTask(Action task) { var ret = Task.Factory.StartNew(task, CancellationToken.None, TaskCreationOptions.None, _unityScheduler); ret.AppendExceptionLogging(); return ret; } /// /// Creates and dispatches a to run on the Unity Scheduler. /// /// The to be executed on the Unity Scheduler. /// /// A that represents the asynchronous operation. This /// will log any exceptions that occur during its execution using the Unity logging system. /// public static Task MainThreadTask(Func task) { var ret = Task.Factory.StartNew(task, CancellationToken.None, TaskCreationOptions.None, _unityScheduler).Unwrap(); ret.AppendExceptionLogging(); return ret; } /// /// Creates and dispatches a with a parameter to run on the Unity Scheduler. /// /// The type of the parameter passed to the task. /// The to be executed on the Unity Scheduler. /// The parameter to pass to the task. /// /// A that represents the asynchronous operation. This /// will log any exceptions that occur during its execution using the Unity logging system. /// public static Task MainThreadTask(Func task, T parameter) { var ret = Task.Factory.StartNew(task, parameter, CancellationToken.None, TaskCreationOptions.None, _unityScheduler).Unwrap(); ret.AppendExceptionLogging(); return ret; } /// /// Creates and dispatches a to run on the Unity Scheduler. /// /// The type of the result produced by the task. /// The to be executed on the Unity Scheduler. /// /// A that represents the asynchronous operation. This /// will log any exceptions that occur during its execution using the Unity logging system and will /// return the result of type upon completion. /// public static Task MainThreadTask(Func> task) { var ret = Task.Factory.StartNew(task, CancellationToken.None, TaskCreationOptions.None, _unityScheduler).Unwrap(); ret.AppendExceptionLogging(); return ret; } /// /// Creates and dispatches a with a parameter to run on the Unity Scheduler. /// /// The type of the parameter passed to the task. /// The type of the result produced by the task. /// The to be executed on the Unity Scheduler. /// The parameter to pass to the task. /// /// A that represents the asynchronous operation. This /// will log any exceptions that occur during its execution using the Unity logging system and will /// return the result of type upon completion. /// public static Task MainThreadTask(Func> task, T parameter) { var ret = Task.Factory.StartNew(task, parameter, CancellationToken.None, TaskCreationOptions.None, _unityScheduler).Unwrap(); ret.AppendExceptionLogging(); return ret; } /// /// Creates a continuation that executes asynchronously, on the Unity main thread, when the target completes. /// /// Target . /// An action to run when the completes. /// The type of the result produced by the . /// A new continuation . public static Task ContinueWithOnMainThread(this Task task, Action> continuation) { var ret = Task.Factory.StartNew(async () => { await task; continuation.Invoke(task); }, CancellationToken.None, TaskCreationOptions.None, _unityScheduler).Unwrap(); ret.AppendExceptionLogging(); return ret; } /// /// Creates a continuation that executes asynchronously, on the Unity main thread, when the target completes. /// /// Target . /// An action to run when the completes. /// The type of the result produced by the . /// A new continuation . public static Task ContinueWithOnMainThread(this Task task, Action continuation) { var ret = Task.Factory.StartNew(async () => { await task; continuation.Invoke(task); }, CancellationToken.None, TaskCreationOptions.None, _unityScheduler).Unwrap(); ret.AppendExceptionLogging(); return ret; } private static void AppendExceptionLogging(this Task inputTask) => inputTask.ContinueWith(faultedTask => LogController.LogException(faultedTask.Exception), TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously); private static SynchronizationContext _context; private static TaskScheduler _unityScheduler; #if UNITY_EDITOR [InitializeOnLoadMethod] #endif [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] private static void _initialize() { _context ??= SynchronizationContext.Current; _unityScheduler ??= TaskScheduler.FromCurrentSynchronizationContext(); } } }