123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- using System.Collections;
- using UnityEngine;
- using System.Threading;
- namespace UnityAsync
- {
- [AddComponentMenu("")] // don't show in menu
- public partial class AsyncManager : MonoBehaviour
- {
- /// <summary>
- /// The frame count in the currently active update loop.
- /// </summary>
- public static int CurrentFrameCount { get; private set; }
-
- /// <summary>
- /// The time in the currently active update loop.
- /// </summary>
- public static float CurrentTime { get; private set; }
-
- /// <summary>
- /// The unscaled time in the currently active update loop.
- /// </summary>
- public static float CurrentUnscaledTime { get; private set; }
-
- /// <summary>
- /// Unity's <see cref="System.Threading.SynchronizationContext"/>.
- /// </summary>
- public static SynchronizationContext UnitySyncContext { get; private set; }
-
- /// <summary>
- /// Background (thread pool) <see cref="System.Threading.SynchronizationContext"/>.
- /// </summary>
- public static SynchronizationContext BackgroundSyncContext { get; private set; }
-
- /// <summary>
- /// Returns true if called from Unity's <see cref="System.Threading.SynchronizationContext"/>.
- /// </summary>
- public static bool InUnityContext => Thread.CurrentThread.ManagedThreadId == unityThreadId;
- public static AsyncManager Instance { get; private set; }
- static int unityThreadId, updateCount, lateCount, fixedCount;
- static ContinuationProcessorGroup updates, lateUpdates, fixedUpdates;
- [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
- static void Initialize()
- {
- unityThreadId = Thread.CurrentThread.ManagedThreadId;
- UnitySyncContext = SynchronizationContext.Current;
- BackgroundSyncContext = new SynchronizationContext(); // TODO: confirm this produces desired behaviour
- updates = new ContinuationProcessorGroup();
- lateUpdates = new ContinuationProcessorGroup();
- fixedUpdates = new ContinuationProcessorGroup();
- Instance = new GameObject("Async Manager").AddComponent<AsyncManager>();
-
- DontDestroyOnLoad(Instance);
- }
- /// <summary>
- /// Initializes the manager explicitly. Typically used when running Unity Editor tests (NUnit unit tests).
- /// </summary>
- public static void InitializeForEditorTests()
- {
- Initialize();
-
- // Do not run tasks in background when testing:
- BackgroundSyncContext = UnitySyncContext;
- }
- /// <summary>
- /// Queues a continuation.
- /// Intended for internal use only - you shouldn't need to invoke this.
- /// </summary>
- public static void AddContinuation<T>(in T cont) where T : IAwaitInstructionAwaiter
- {
- switch(cont.Scheduler)
- {
- case FrameScheduler.Update:
- updates.Add(cont);
- break;
- case FrameScheduler.LateUpdate:
- lateUpdates.Add(cont);
- break;
- case FrameScheduler.FixedUpdate:
- fixedUpdates.Add(cont);
- break;
- }
- }
- /// <summary>
- /// Start a coroutine from any context without requiring a MonoBehaviour.
- /// </summary>
- public new static Coroutine StartCoroutine(IEnumerator coroutine) => ((MonoBehaviour)Instance).StartCoroutine(coroutine);
- void Update()
- {
- CurrentFrameCount = ++updateCount;
-
- if(CurrentFrameCount <= 1)
- return;
-
- CurrentTime = Time.time;
- CurrentUnscaledTime = Time.unscaledTime;
-
- updates.Process();
- }
- void LateUpdate()
- {
- CurrentFrameCount = ++lateCount;
-
- if(CurrentFrameCount <= 1)
- return;
-
- lateUpdates.Process();
- }
- void FixedUpdate()
- {
- CurrentFrameCount = ++fixedCount;
-
- if(CurrentFrameCount <= 1)
- return;
-
- fixedUpdates.Process();
- }
- }
- }
|