AsyncTask.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /****************************************************************************
  2. * Copyright 2019 Nreal Techonology Limited. All rights reserved.
  3. *
  4. * This file is part of NRSDK.
  5. *
  6. * https://www.nreal.ai/
  7. *
  8. *****************************************************************************/
  9. namespace NRKernal
  10. {
  11. using System;
  12. using System.Collections.Generic;
  13. using UnityEngine;
  14. /// <summary> A class used for monitoring the status of an asynchronous task. </summary>
  15. /// <typeparam name="T"> The resultant type of the task.</typeparam>
  16. public class AsyncTask<T>
  17. {
  18. /// <summary>
  19. /// A collection of actons to perform on the main Unity thread after the task is complete. </summary>
  20. private List<Action<T>> m_ActionsUponTaskCompletion;
  21. /// <summary> Constructor for AsyncTask. </summary>
  22. /// <param name="asyncOperationComplete"> [out] A callback that, when invoked, changes the status
  23. /// of the task to complete and sets the result based on
  24. /// the argument supplied.</param>
  25. public AsyncTask(out Action<T> asyncOperationComplete)
  26. {
  27. // Register for early update event.
  28. if (!AsyncTask.IsInitialized)
  29. {
  30. AsyncTask.Init();
  31. }
  32. IsComplete = false;
  33. asyncOperationComplete = delegate (T result)
  34. {
  35. Result = result;
  36. IsComplete = true;
  37. if (m_ActionsUponTaskCompletion != null)
  38. {
  39. AsyncTask.PerformActionInUpdate(() =>
  40. {
  41. for (int i = 0; i < m_ActionsUponTaskCompletion.Count; i++)
  42. {
  43. m_ActionsUponTaskCompletion[i](result);
  44. }
  45. });
  46. }
  47. };
  48. }
  49. /// <summary> Constructor for AsyncTask that creates a completed task. </summary>
  50. /// <param name="result"> The result of the completed task.</param>
  51. internal AsyncTask(T result)
  52. {
  53. Result = result;
  54. IsComplete = true;
  55. }
  56. /// <summary> Gets or sets a value indicating whether the task is complete. </summary>
  57. /// <value> <c>true</c> if the task is complete, otherwise <c>false</c>. </value>
  58. public bool IsComplete { get; private set; }
  59. /// <summary> Gets or sets the result of a completed task. </summary>
  60. /// <value> The result of the completed task. </value>
  61. public T Result { get; private set; }
  62. /// <summary>
  63. /// Returns a yield instruction that monitors this task for completion within a coroutine. </summary>
  64. /// <returns> A yield instruction that monitors this task for completion. </returns>
  65. public CustomYieldInstruction WaitForCompletion()
  66. {
  67. return new WaitForTaskCompletionYieldInstruction<T>(this);
  68. }
  69. /// <summary>
  70. /// Performs an action (callback) in the first Unity Update() call after task completion. </summary>
  71. /// <param name="doAfterTaskComplete"> The action to invoke when task is complete. The result
  72. /// of the task will be passed as an argument to the action.</param>
  73. /// <returns> The invoking asynchronous task. </returns>
  74. public AsyncTask<T> ThenAction(Action<T> doAfterTaskComplete)
  75. {
  76. // Perform action now if task is already complete.
  77. if (IsComplete)
  78. {
  79. doAfterTaskComplete(Result);
  80. return this;
  81. }
  82. // Allocate list if needed (avoids allocation if then is not used).
  83. if (m_ActionsUponTaskCompletion == null)
  84. {
  85. m_ActionsUponTaskCompletion = new List<Action<T>>();
  86. }
  87. m_ActionsUponTaskCompletion.Add(doAfterTaskComplete);
  88. return this;
  89. }
  90. }
  91. /// <summary> Helper methods for dealing with asynchronous tasks. </summary>
  92. internal class AsyncTask
  93. {
  94. /// <summary> Queue of update actions. </summary>
  95. private static Queue<Action> m_UpdateActionQueue = new Queue<Action>();
  96. /// <summary> The lock object. </summary>
  97. private static object m_LockObject = new object();
  98. /// <summary> Gets or sets a value indicating whether this object is initialized. </summary>
  99. /// <value> True if this object is initialized, false if not. </value>
  100. public static bool IsInitialized { get; private set; }
  101. /// <summary>
  102. /// Queues an action to be performed on Unity thread in Update(). This method can be called by
  103. /// any thread. </summary>
  104. /// <param name="action"> The action to perform.</param>
  105. public static void PerformActionInUpdate(Action action)
  106. {
  107. lock (m_LockObject)
  108. {
  109. m_UpdateActionQueue.Enqueue(action);
  110. }
  111. }
  112. /// <summary> An Update handler called each frame. </summary>
  113. public static void OnUpdate()
  114. {
  115. if (m_UpdateActionQueue.Count == 0)
  116. {
  117. return;
  118. }
  119. lock (m_LockObject)
  120. {
  121. while (m_UpdateActionQueue.Count > 0)
  122. {
  123. Action action = m_UpdateActionQueue.Dequeue();
  124. action();
  125. }
  126. }
  127. }
  128. /// <summary> Initializes this object. </summary>
  129. public static void Init()
  130. {
  131. if (IsInitialized)
  132. {
  133. return;
  134. }
  135. NRKernalUpdater.OnUpdate += OnUpdate;
  136. IsInitialized = true;
  137. }
  138. }
  139. }