using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Text; using System.Threading; using UnityEngine; namespace QuestAppLauncher { public class AsyncCoroutineRunner : MonoBehaviour { static AsyncCoroutineRunner _instance; public static AsyncCoroutineRunner Instance { get { if (_instance == null) { _instance = new GameObject("AsyncCoroutineRunner") .AddComponent(); } return _instance; } } void Awake() { // Don't show in scene hierarchy gameObject.hideFlags = HideFlags.HideAndDontSave; DontDestroyOnLoad(gameObject); } } public static class IEnumeratorAwaitExtensions { public static SimpleCoroutineAwaiter GetAwaiter(this AsyncOperation instruction) { return GetAwaiterReturnSelf(instruction); } static SimpleCoroutineAwaiter GetAwaiterReturnSelf(T instruction) { var awaiter = new SimpleCoroutineAwaiter(); RunOnUnityScheduler(() => AsyncCoroutineRunner.Instance.StartCoroutine( InstructionWrappers.ReturnSelf(awaiter, instruction))); return awaiter; } static void RunOnUnityScheduler(Action action) { if (SynchronizationContext.Current == SyncContextUtil.UnitySynchronizationContext) { action(); } else { SyncContextUtil.UnitySynchronizationContext.Post(_ => action(), null); } } public class SimpleCoroutineAwaiter : INotifyCompletion { bool _isDone; Exception _exception; Action _continuation; T _result; public bool IsCompleted { get { return _isDone; } } public T GetResult() { Debug.Assert(_isDone); if (_exception != null) { ExceptionDispatchInfo.Capture(_exception).Throw(); } return _result; } public void Complete(T result, Exception e) { Debug.Assert(!_isDone); _isDone = true; _exception = e; _result = result; // Always trigger the continuation on the unity thread when awaiting on unity yield // instructions if (_continuation != null) { RunOnUnityScheduler(_continuation); } } void INotifyCompletion.OnCompleted(Action continuation) { Debug.Assert(_continuation == null); Debug.Assert(!_isDone); _continuation = continuation; } } static class InstructionWrappers { public static IEnumerator ReturnSelf( SimpleCoroutineAwaiter awaiter, T instruction) { yield return instruction; awaiter.Complete(instruction, null); } } public static class SyncContextUtil { [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] static void Install() { UnitySynchronizationContext = SynchronizationContext.Current; UnityThreadId = Thread.CurrentThread.ManagedThreadId; } public static int UnityThreadId { get; private set; } public static SynchronizationContext UnitySynchronizationContext { get; private set; } } } }