/****************************************************************************
* 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;
}
}
}