/**************************************************************************** * Copyright 2019 Nreal Techonology Limited. All rights reserved. * * This file is part of NRSDK. * * https://www.nreal.ai/ * *****************************************************************************/ namespace NRKernal { using System; using System.Collections.Generic; using UnityEngine; /// A class used for monitoring the status of an asynchronous task. /// The resultant type of the task. public class AsyncTask { /// /// A collection of actons to perform on the main Unity thread after the task is complete. private List> m_ActionsUponTaskCompletion; /// Constructor for AsyncTask. /// [out] A callback that, when invoked, changes the status /// of the task to complete and sets the result based on /// the argument supplied. public AsyncTask(out Action asyncOperationComplete) { // Register for early update event. if (!AsyncTask.IsInitialized) { AsyncTask.Init(); } IsComplete = false; asyncOperationComplete = delegate (T result) { Result = result; IsComplete = true; if (m_ActionsUponTaskCompletion != null) { AsyncTask.PerformActionInUpdate(() => { for (int i = 0; i < m_ActionsUponTaskCompletion.Count; i++) { m_ActionsUponTaskCompletion[i](result); } }); } }; } /// Constructor for AsyncTask that creates a completed task. /// The result of the completed task. internal AsyncTask(T result) { Result = result; IsComplete = true; } /// Gets or sets a value indicating whether the task is complete. /// true if the task is complete, otherwise false. public bool IsComplete { get; private set; } /// Gets or sets the result of a completed task. /// The result of the completed task. public T Result { get; private set; } /// /// Returns a yield instruction that monitors this task for completion within a coroutine. /// A yield instruction that monitors this task for completion. public CustomYieldInstruction WaitForCompletion() { return new WaitForTaskCompletionYieldInstruction(this); } /// /// Performs an action (callback) in the first Unity Update() call after task completion. /// The action to invoke when task is complete. The result /// of the task will be passed as an argument to the action. /// The invoking asynchronous task. public AsyncTask ThenAction(Action doAfterTaskComplete) { // Perform action now if task is already complete. if (IsComplete) { doAfterTaskComplete(Result); return this; } // Allocate list if needed (avoids allocation if then is not used). if (m_ActionsUponTaskCompletion == null) { m_ActionsUponTaskCompletion = new List>(); } m_ActionsUponTaskCompletion.Add(doAfterTaskComplete); return this; } } /// Helper methods for dealing with asynchronous tasks. internal class AsyncTask { /// Queue of update actions. private static Queue m_UpdateActionQueue = new Queue(); /// The lock object. private static object m_LockObject = new object(); /// Gets or sets a value indicating whether this object is initialized. /// True if this object is initialized, false if not. public static bool IsInitialized { get; private set; } /// /// Queues an action to be performed on Unity thread in Update(). This method can be called by /// any thread. /// The action to perform. public static void PerformActionInUpdate(Action action) { lock (m_LockObject) { m_UpdateActionQueue.Enqueue(action); } } /// An Update handler called each frame. public static void OnUpdate() { if (m_UpdateActionQueue.Count == 0) { return; } lock (m_LockObject) { while (m_UpdateActionQueue.Count > 0) { Action action = m_UpdateActionQueue.Dequeue(); action(); } } } /// Initializes this object. public static void Init() { if (IsInitialized) { return; } NRKernalUpdater.OnUpdate += OnUpdate; IsInitialized = true; } } }