// Copyright (c) 2015 - 2023 Doozy Entertainment. All Rights Reserved. // This code can only be used under the standard Unity Asset Store End User License Agreement // A Copy of the EULA APPENDIX 1 is available at http://unity3d.com/company/legal/as_terms using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; // ReSharper disable MemberCanBePrivate.Global // ReSharper disable UnusedAutoPropertyAccessor.Global namespace Doozy.Runtime.Common { /// /// Specialized class that allows call a method on the main thread. /// This is useful when you have to call a Unity API from a thread that is not the main thread. /// public class SyncContext : SingletonBehaviour { /// Task scheduler that runs tasks on the main thread public static TaskScheduler unityTaskScheduler { get; private set; } /// Unity's main thread public static int unityThread { get; private set; } /// Synchronization context for the main thread public static SynchronizationContext unitySynchronizationContext { get; private set; } /// Queue of tasks to be executed on the main thread public static Queue runInUpdate { get; } = new Queue(); /// Returns TRUE if the current thread is the Unity main thread public static bool isOnUnityThread => unityThread == Thread.CurrentThread.ManagedThreadId; protected override void Awake() { base.Awake(); unitySynchronizationContext = SynchronizationContext.Current; unityThread = Thread.CurrentThread.ManagedThreadId; unityTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext(); } private void Update() { //if there are no actions in the queue, do nothing while (runInUpdate.Count > 0) { Action action = null; lock (runInUpdate) { if (runInUpdate.Count > 0) action = runInUpdate.Dequeue(); } action?.Invoke(); } } public static void Initialize() { _ = instance; } /// Runs the given action on the main thread /// Action to run on the main thread public static void RunOnUnityThread(Action action) { Initialize(); if (unityThread == Thread.CurrentThread.ManagedThreadId) //if we are already on the main thread, just run the action { action(); return; } //if we are not on the main thread, add the action to the queue lock (runInUpdate) { runInUpdate.Enqueue(action); } } } }