using System; using System.Collections.Concurrent; using System.Threading; using System.Threading.Tasks; using UnityEngine; namespace Unity.XR.XREAL { /// /// A singleton MonoBehaviour class that dispatches actions to be executed on the Unity main thread. /// public class XREALMainThreadDispather : SingletonMonoBehaviour { ConcurrentQueue m_Actions = new ConcurrentQueue(); ConcurrentQueue m_RunningActions = new ConcurrentQueue(); /// /// Event invoked every frame during the Update method. /// public static event Action OnUpdate; /// /// Queues an action to be executed on the Unity main thread in the next frame. /// /// The action to execute on the main thread. public void QueueOnMainThread(Action action) { m_Actions.Enqueue(action); } /// /// Queues an action to be executed on the Unity main thread after a specified delay. /// Returns a CancellationTokenSource that can be used to cancel the scheduled action. /// /// The action to execute on the main thread. /// The delay in seconds before the action is executed. /// A CancellationTokenSource that can be used to cancel the scheduled action. public CancellationTokenSource QueueOnMainThreadWithDelay(Action action, float delaySeconds) { CancellationTokenSource ctSource = new CancellationTokenSource(); Task.Run(async () => { await Task.Delay(TimeSpan.FromSeconds(delaySeconds)); if (!ctSource.IsCancellationRequested) m_Actions.Enqueue(action); }, ctSource.Token); return ctSource; } void Update() { OnUpdate?.Invoke(); if (m_Actions.Count > 0) { (m_Actions, m_RunningActions) = (m_RunningActions, m_Actions); while (m_RunningActions.TryDequeue(out var action)) { try { action.Invoke(); } catch (Exception e) { Debug.LogException(e); } } } } #if UNITY_ANDROID && !UNITY_EDITOR void OnApplicationPause(bool pause) { Debug.Log($"[XREALMainThreadDispather] OnApplicationPause: {pause}"); if (pause) { XREALPlugin.PauseSession(); } else { XREALPlugin.ResumeSession(); } } #endif } }