Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 

386 linhas
15 KiB

  1. // AsyncInstantiateOperation was added since Unity 2022.3.20 / 2023.3.0b7
  2. #if UNITY_2022_3 && !(UNITY_2022_3_0 || UNITY_2022_3_1 || UNITY_2022_3_2 || UNITY_2022_3_3 || UNITY_2022_3_4 || UNITY_2022_3_5 || UNITY_2022_3_6 || UNITY_2022_3_7 || UNITY_2022_3_8 || UNITY_2022_3_9 || UNITY_2022_3_10 || UNITY_2022_3_11 || UNITY_2022_3_12 || UNITY_2022_3_13 || UNITY_2022_3_14 || UNITY_2022_3_15 || UNITY_2022_3_16 || UNITY_2022_3_17 || UNITY_2022_3_18 || UNITY_2022_3_19)
  3. #define UNITY_2022_SUPPORT
  4. #endif
  5. #if UNITY_2022_SUPPORT || UNITY_2023_3_OR_NEWER
  6. using Cysharp.Threading.Tasks.Internal;
  7. using System;
  8. using System.Threading;
  9. using UnityEngine;
  10. namespace Cysharp.Threading.Tasks
  11. {
  12. public static class AsyncInstantiateOperationExtensions
  13. {
  14. // AsyncInstantiateOperation<T> has GetAwaiter so no need to impl
  15. // public static UniTask<T[]>.Awaiter GetAwaiter<T>(this AsyncInstantiateOperation<T> operation) where T : Object
  16. public static UniTask<UnityEngine.Object[]> WithCancellation<T>(this AsyncInstantiateOperation asyncOperation, CancellationToken cancellationToken)
  17. {
  18. return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
  19. }
  20. public static UniTask<UnityEngine.Object[]> WithCancellation<T>(this AsyncInstantiateOperation asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
  21. {
  22. return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
  23. }
  24. public static UniTask<UnityEngine.Object[]> ToUniTask(this AsyncInstantiateOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
  25. {
  26. Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
  27. if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object[]>(cancellationToken);
  28. if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.Result);
  29. return new UniTask<UnityEngine.Object[]>(AsyncInstantiateOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
  30. }
  31. public static UniTask<T[]> WithCancellation<T>(this AsyncInstantiateOperation<T> asyncOperation, CancellationToken cancellationToken)
  32. where T : UnityEngine.Object
  33. {
  34. return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
  35. }
  36. public static UniTask<T[]> WithCancellation<T>(this AsyncInstantiateOperation<T> asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
  37. where T : UnityEngine.Object
  38. {
  39. return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
  40. }
  41. public static UniTask<T[]> ToUniTask<T>(this AsyncInstantiateOperation<T> asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
  42. where T : UnityEngine.Object
  43. {
  44. Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
  45. if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<T[]>(cancellationToken);
  46. if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.Result);
  47. return new UniTask<T[]>(AsyncInstantiateOperationConfiguredSource<T>.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
  48. }
  49. sealed class AsyncInstantiateOperationConfiguredSource : IUniTaskSource<UnityEngine.Object[]>, IPlayerLoopItem, ITaskPoolNode<AsyncInstantiateOperationConfiguredSource>
  50. {
  51. static TaskPool<AsyncInstantiateOperationConfiguredSource> pool;
  52. AsyncInstantiateOperationConfiguredSource nextNode;
  53. public ref AsyncInstantiateOperationConfiguredSource NextNode => ref nextNode;
  54. static AsyncInstantiateOperationConfiguredSource()
  55. {
  56. TaskPool.RegisterSizeGetter(typeof(AsyncInstantiateOperationConfiguredSource), () => pool.Size);
  57. }
  58. AsyncInstantiateOperation asyncOperation;
  59. IProgress<float> progress;
  60. CancellationToken cancellationToken;
  61. CancellationTokenRegistration cancellationTokenRegistration;
  62. bool cancelImmediately;
  63. bool completed;
  64. UniTaskCompletionSourceCore<UnityEngine.Object[]> core;
  65. Action<AsyncOperation> continuationAction;
  66. AsyncInstantiateOperationConfiguredSource()
  67. {
  68. continuationAction = Continuation;
  69. }
  70. public static IUniTaskSource<UnityEngine.Object[]> Create(AsyncInstantiateOperation asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
  71. {
  72. if (cancellationToken.IsCancellationRequested)
  73. {
  74. return AutoResetUniTaskCompletionSource<UnityEngine.Object[]>.CreateFromCanceled(cancellationToken, out token);
  75. }
  76. if (!pool.TryPop(out var result))
  77. {
  78. result = new AsyncInstantiateOperationConfiguredSource();
  79. }
  80. result.asyncOperation = asyncOperation;
  81. result.progress = progress;
  82. result.cancellationToken = cancellationToken;
  83. result.cancelImmediately = cancelImmediately;
  84. result.completed = false;
  85. asyncOperation.completed += result.continuationAction;
  86. if (cancelImmediately && cancellationToken.CanBeCanceled)
  87. {
  88. result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
  89. {
  90. var source = (AsyncInstantiateOperationConfiguredSource)state;
  91. source.core.TrySetCanceled(source.cancellationToken);
  92. }, result);
  93. }
  94. TaskTracker.TrackActiveTask(result, 3);
  95. PlayerLoopHelper.AddAction(timing, result);
  96. token = result.core.Version;
  97. return result;
  98. }
  99. public UnityEngine.Object[] GetResult(short token)
  100. {
  101. try
  102. {
  103. return core.GetResult(token);
  104. }
  105. finally
  106. {
  107. if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
  108. {
  109. TryReturn();
  110. }
  111. else
  112. {
  113. TaskTracker.RemoveTracking(this);
  114. }
  115. }
  116. }
  117. void IUniTaskSource.GetResult(short token)
  118. {
  119. GetResult(token);
  120. }
  121. public UniTaskStatus GetStatus(short token)
  122. {
  123. return core.GetStatus(token);
  124. }
  125. public UniTaskStatus UnsafeGetStatus()
  126. {
  127. return core.UnsafeGetStatus();
  128. }
  129. public void OnCompleted(Action<object> continuation, object state, short token)
  130. {
  131. core.OnCompleted(continuation, state, token);
  132. }
  133. public bool MoveNext()
  134. {
  135. // Already completed
  136. if (completed || asyncOperation == null)
  137. {
  138. return false;
  139. }
  140. if (cancellationToken.IsCancellationRequested)
  141. {
  142. core.TrySetCanceled(cancellationToken);
  143. return false;
  144. }
  145. if (progress != null)
  146. {
  147. progress.Report(asyncOperation.progress);
  148. }
  149. if (asyncOperation.isDone)
  150. {
  151. core.TrySetResult(asyncOperation.Result);
  152. return false;
  153. }
  154. return true;
  155. }
  156. bool TryReturn()
  157. {
  158. TaskTracker.RemoveTracking(this);
  159. core.Reset();
  160. asyncOperation.completed -= continuationAction;
  161. asyncOperation = default;
  162. progress = default;
  163. cancellationToken = default;
  164. cancellationTokenRegistration.Dispose();
  165. cancelImmediately = default;
  166. return pool.TryPush(this);
  167. }
  168. void Continuation(AsyncOperation _)
  169. {
  170. if (completed)
  171. {
  172. return;
  173. }
  174. completed = true;
  175. if (cancellationToken.IsCancellationRequested)
  176. {
  177. core.TrySetCanceled(cancellationToken);
  178. }
  179. else
  180. {
  181. core.TrySetResult(asyncOperation.Result);
  182. }
  183. }
  184. }
  185. sealed class AsyncInstantiateOperationConfiguredSource<T> : IUniTaskSource<T[]>, IPlayerLoopItem, ITaskPoolNode<AsyncInstantiateOperationConfiguredSource<T>>
  186. where T : UnityEngine.Object
  187. {
  188. static TaskPool<AsyncInstantiateOperationConfiguredSource<T>> pool;
  189. AsyncInstantiateOperationConfiguredSource<T> nextNode;
  190. public ref AsyncInstantiateOperationConfiguredSource<T> NextNode => ref nextNode;
  191. static AsyncInstantiateOperationConfiguredSource()
  192. {
  193. TaskPool.RegisterSizeGetter(typeof(AsyncInstantiateOperationConfiguredSource<T>), () => pool.Size);
  194. }
  195. AsyncInstantiateOperation<T> asyncOperation;
  196. IProgress<float> progress;
  197. CancellationToken cancellationToken;
  198. CancellationTokenRegistration cancellationTokenRegistration;
  199. bool cancelImmediately;
  200. bool completed;
  201. UniTaskCompletionSourceCore<T[]> core;
  202. Action<AsyncOperation> continuationAction;
  203. AsyncInstantiateOperationConfiguredSource()
  204. {
  205. continuationAction = Continuation;
  206. }
  207. public static IUniTaskSource<T[]> Create(AsyncInstantiateOperation<T> asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
  208. {
  209. if (cancellationToken.IsCancellationRequested)
  210. {
  211. return AutoResetUniTaskCompletionSource<T[]>.CreateFromCanceled(cancellationToken, out token);
  212. }
  213. if (!pool.TryPop(out var result))
  214. {
  215. result = new AsyncInstantiateOperationConfiguredSource<T>();
  216. }
  217. result.asyncOperation = asyncOperation;
  218. result.progress = progress;
  219. result.cancellationToken = cancellationToken;
  220. result.cancelImmediately = cancelImmediately;
  221. result.completed = false;
  222. asyncOperation.completed += result.continuationAction;
  223. if (cancelImmediately && cancellationToken.CanBeCanceled)
  224. {
  225. result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
  226. {
  227. var source = (AsyncInstantiateOperationConfiguredSource<T>)state;
  228. source.core.TrySetCanceled(source.cancellationToken);
  229. }, result);
  230. }
  231. TaskTracker.TrackActiveTask(result, 3);
  232. PlayerLoopHelper.AddAction(timing, result);
  233. token = result.core.Version;
  234. return result;
  235. }
  236. public T[] GetResult(short token)
  237. {
  238. try
  239. {
  240. return core.GetResult(token);
  241. }
  242. finally
  243. {
  244. if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
  245. {
  246. TryReturn();
  247. }
  248. else
  249. {
  250. TaskTracker.RemoveTracking(this);
  251. }
  252. }
  253. }
  254. void IUniTaskSource.GetResult(short token)
  255. {
  256. GetResult(token);
  257. }
  258. public UniTaskStatus GetStatus(short token)
  259. {
  260. return core.GetStatus(token);
  261. }
  262. public UniTaskStatus UnsafeGetStatus()
  263. {
  264. return core.UnsafeGetStatus();
  265. }
  266. public void OnCompleted(Action<object> continuation, object state, short token)
  267. {
  268. core.OnCompleted(continuation, state, token);
  269. }
  270. public bool MoveNext()
  271. {
  272. // Already completed
  273. if (completed || asyncOperation == null)
  274. {
  275. return false;
  276. }
  277. if (cancellationToken.IsCancellationRequested)
  278. {
  279. core.TrySetCanceled(cancellationToken);
  280. return false;
  281. }
  282. if (progress != null)
  283. {
  284. progress.Report(asyncOperation.progress);
  285. }
  286. if (asyncOperation.isDone)
  287. {
  288. core.TrySetResult(asyncOperation.Result);
  289. return false;
  290. }
  291. return true;
  292. }
  293. bool TryReturn()
  294. {
  295. TaskTracker.RemoveTracking(this);
  296. core.Reset();
  297. asyncOperation.completed -= continuationAction;
  298. asyncOperation = default;
  299. progress = default;
  300. cancellationToken = default;
  301. cancellationTokenRegistration.Dispose();
  302. cancelImmediately = default;
  303. return pool.TryPush(this);
  304. }
  305. void Continuation(AsyncOperation _)
  306. {
  307. if (completed)
  308. {
  309. return;
  310. }
  311. completed = true;
  312. if (cancellationToken.IsCancellationRequested)
  313. {
  314. core.TrySetCanceled(cancellationToken);
  315. }
  316. else
  317. {
  318. core.TrySetResult(asyncOperation.Result);
  319. }
  320. }
  321. }
  322. }
  323. }
  324. #endif