UnityAsyncExtensions.cs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928
  1. #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
  2. using System;
  3. using System.Runtime.CompilerServices;
  4. using System.Threading;
  5. using UnityEngine;
  6. using Cysharp.Threading.Tasks.Internal;
  7. #if ENABLE_UNITYWEBREQUEST && (!UNITY_2019_1_OR_NEWER || UNITASK_WEBREQUEST_SUPPORT)
  8. using UnityEngine.Networking;
  9. #endif
  10. namespace Cysharp.Threading.Tasks
  11. {
  12. public static partial class UnityAsyncExtensions
  13. {
  14. #region AsyncOperation
  15. public static AsyncOperationAwaiter GetAwaiter(this AsyncOperation asyncOperation)
  16. {
  17. Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
  18. return new AsyncOperationAwaiter(asyncOperation);
  19. }
  20. public static UniTask WithCancellation(this AsyncOperation asyncOperation, CancellationToken cancellationToken)
  21. {
  22. return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
  23. }
  24. public static UniTask ToUniTask(this AsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
  25. {
  26. Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
  27. if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled(cancellationToken);
  28. if (asyncOperation.isDone) return UniTask.CompletedTask;
  29. return new UniTask(AsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
  30. }
  31. public struct AsyncOperationAwaiter : ICriticalNotifyCompletion
  32. {
  33. AsyncOperation asyncOperation;
  34. Action<AsyncOperation> continuationAction;
  35. public AsyncOperationAwaiter(AsyncOperation asyncOperation)
  36. {
  37. this.asyncOperation = asyncOperation;
  38. this.continuationAction = null;
  39. }
  40. public bool IsCompleted => asyncOperation.isDone;
  41. public void GetResult()
  42. {
  43. if (continuationAction != null)
  44. {
  45. asyncOperation.completed -= continuationAction;
  46. continuationAction = null;
  47. asyncOperation = null;
  48. }
  49. else
  50. {
  51. asyncOperation = null;
  52. }
  53. }
  54. public void OnCompleted(Action continuation)
  55. {
  56. UnsafeOnCompleted(continuation);
  57. }
  58. public void UnsafeOnCompleted(Action continuation)
  59. {
  60. Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
  61. continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
  62. asyncOperation.completed += continuationAction;
  63. }
  64. }
  65. sealed class AsyncOperationConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationConfiguredSource>
  66. {
  67. static TaskPool<AsyncOperationConfiguredSource> pool;
  68. AsyncOperationConfiguredSource nextNode;
  69. public ref AsyncOperationConfiguredSource NextNode => ref nextNode;
  70. static AsyncOperationConfiguredSource()
  71. {
  72. TaskPool.RegisterSizeGetter(typeof(AsyncOperationConfiguredSource), () => pool.Size);
  73. }
  74. AsyncOperation asyncOperation;
  75. IProgress<float> progress;
  76. CancellationToken cancellationToken;
  77. UniTaskCompletionSourceCore<AsyncUnit> core;
  78. AsyncOperationConfiguredSource()
  79. {
  80. }
  81. public static IUniTaskSource Create(AsyncOperation asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
  82. {
  83. if (cancellationToken.IsCancellationRequested)
  84. {
  85. return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
  86. }
  87. if (!pool.TryPop(out var result))
  88. {
  89. result = new AsyncOperationConfiguredSource();
  90. }
  91. result.asyncOperation = asyncOperation;
  92. result.progress = progress;
  93. result.cancellationToken = cancellationToken;
  94. TaskTracker.TrackActiveTask(result, 3);
  95. PlayerLoopHelper.AddAction(timing, result);
  96. token = result.core.Version;
  97. return result;
  98. }
  99. public void GetResult(short token)
  100. {
  101. try
  102. {
  103. core.GetResult(token);
  104. }
  105. finally
  106. {
  107. TryReturn();
  108. }
  109. }
  110. public UniTaskStatus GetStatus(short token)
  111. {
  112. return core.GetStatus(token);
  113. }
  114. public UniTaskStatus UnsafeGetStatus()
  115. {
  116. return core.UnsafeGetStatus();
  117. }
  118. public void OnCompleted(Action<object> continuation, object state, short token)
  119. {
  120. core.OnCompleted(continuation, state, token);
  121. }
  122. public bool MoveNext()
  123. {
  124. if (cancellationToken.IsCancellationRequested)
  125. {
  126. core.TrySetCanceled(cancellationToken);
  127. return false;
  128. }
  129. if (progress != null)
  130. {
  131. progress.Report(asyncOperation.progress);
  132. }
  133. if (asyncOperation.isDone)
  134. {
  135. core.TrySetResult(AsyncUnit.Default);
  136. return false;
  137. }
  138. return true;
  139. }
  140. bool TryReturn()
  141. {
  142. TaskTracker.RemoveTracking(this);
  143. core.Reset();
  144. asyncOperation = default;
  145. progress = default;
  146. cancellationToken = default;
  147. return pool.TryPush(this);
  148. }
  149. }
  150. #endregion
  151. #region ResourceRequest
  152. public static ResourceRequestAwaiter GetAwaiter(this ResourceRequest asyncOperation)
  153. {
  154. Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
  155. return new ResourceRequestAwaiter(asyncOperation);
  156. }
  157. public static UniTask<UnityEngine.Object> WithCancellation(this ResourceRequest asyncOperation, CancellationToken cancellationToken)
  158. {
  159. return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
  160. }
  161. public static UniTask<UnityEngine.Object> ToUniTask(this ResourceRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
  162. {
  163. Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
  164. if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object>(cancellationToken);
  165. if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset);
  166. return new UniTask<UnityEngine.Object>(ResourceRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
  167. }
  168. public struct ResourceRequestAwaiter : ICriticalNotifyCompletion
  169. {
  170. ResourceRequest asyncOperation;
  171. Action<AsyncOperation> continuationAction;
  172. public ResourceRequestAwaiter(ResourceRequest asyncOperation)
  173. {
  174. this.asyncOperation = asyncOperation;
  175. this.continuationAction = null;
  176. }
  177. public bool IsCompleted => asyncOperation.isDone;
  178. public UnityEngine.Object GetResult()
  179. {
  180. if (continuationAction != null)
  181. {
  182. asyncOperation.completed -= continuationAction;
  183. continuationAction = null;
  184. var result = asyncOperation.asset;
  185. asyncOperation = null;
  186. return result;
  187. }
  188. else
  189. {
  190. var result = asyncOperation.asset;
  191. asyncOperation = null;
  192. return result;
  193. }
  194. }
  195. public void OnCompleted(Action continuation)
  196. {
  197. UnsafeOnCompleted(continuation);
  198. }
  199. public void UnsafeOnCompleted(Action continuation)
  200. {
  201. Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
  202. continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
  203. asyncOperation.completed += continuationAction;
  204. }
  205. }
  206. sealed class ResourceRequestConfiguredSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<ResourceRequestConfiguredSource>
  207. {
  208. static TaskPool<ResourceRequestConfiguredSource> pool;
  209. ResourceRequestConfiguredSource nextNode;
  210. public ref ResourceRequestConfiguredSource NextNode => ref nextNode;
  211. static ResourceRequestConfiguredSource()
  212. {
  213. TaskPool.RegisterSizeGetter(typeof(ResourceRequestConfiguredSource), () => pool.Size);
  214. }
  215. ResourceRequest asyncOperation;
  216. IProgress<float> progress;
  217. CancellationToken cancellationToken;
  218. UniTaskCompletionSourceCore<UnityEngine.Object> core;
  219. ResourceRequestConfiguredSource()
  220. {
  221. }
  222. public static IUniTaskSource<UnityEngine.Object> Create(ResourceRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
  223. {
  224. if (cancellationToken.IsCancellationRequested)
  225. {
  226. return AutoResetUniTaskCompletionSource<UnityEngine.Object>.CreateFromCanceled(cancellationToken, out token);
  227. }
  228. if (!pool.TryPop(out var result))
  229. {
  230. result = new ResourceRequestConfiguredSource();
  231. }
  232. result.asyncOperation = asyncOperation;
  233. result.progress = progress;
  234. result.cancellationToken = cancellationToken;
  235. TaskTracker.TrackActiveTask(result, 3);
  236. PlayerLoopHelper.AddAction(timing, result);
  237. token = result.core.Version;
  238. return result;
  239. }
  240. public UnityEngine.Object GetResult(short token)
  241. {
  242. try
  243. {
  244. return core.GetResult(token);
  245. }
  246. finally
  247. {
  248. TryReturn();
  249. }
  250. }
  251. void IUniTaskSource.GetResult(short token)
  252. {
  253. GetResult(token);
  254. }
  255. public UniTaskStatus GetStatus(short token)
  256. {
  257. return core.GetStatus(token);
  258. }
  259. public UniTaskStatus UnsafeGetStatus()
  260. {
  261. return core.UnsafeGetStatus();
  262. }
  263. public void OnCompleted(Action<object> continuation, object state, short token)
  264. {
  265. core.OnCompleted(continuation, state, token);
  266. }
  267. public bool MoveNext()
  268. {
  269. if (cancellationToken.IsCancellationRequested)
  270. {
  271. core.TrySetCanceled(cancellationToken);
  272. return false;
  273. }
  274. if (progress != null)
  275. {
  276. progress.Report(asyncOperation.progress);
  277. }
  278. if (asyncOperation.isDone)
  279. {
  280. core.TrySetResult(asyncOperation.asset);
  281. return false;
  282. }
  283. return true;
  284. }
  285. bool TryReturn()
  286. {
  287. TaskTracker.RemoveTracking(this);
  288. core.Reset();
  289. asyncOperation = default;
  290. progress = default;
  291. cancellationToken = default;
  292. return pool.TryPush(this);
  293. }
  294. }
  295. #endregion
  296. #if UNITASK_ASSETBUNDLE_SUPPORT
  297. #region AssetBundleRequest
  298. public static AssetBundleRequestAwaiter GetAwaiter(this AssetBundleRequest asyncOperation)
  299. {
  300. Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
  301. return new AssetBundleRequestAwaiter(asyncOperation);
  302. }
  303. public static UniTask<UnityEngine.Object> WithCancellation(this AssetBundleRequest asyncOperation, CancellationToken cancellationToken)
  304. {
  305. return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
  306. }
  307. public static UniTask<UnityEngine.Object> ToUniTask(this AssetBundleRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
  308. {
  309. Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
  310. if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object>(cancellationToken);
  311. if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset);
  312. return new UniTask<UnityEngine.Object>(AssetBundleRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
  313. }
  314. public struct AssetBundleRequestAwaiter : ICriticalNotifyCompletion
  315. {
  316. AssetBundleRequest asyncOperation;
  317. Action<AsyncOperation> continuationAction;
  318. public AssetBundleRequestAwaiter(AssetBundleRequest asyncOperation)
  319. {
  320. this.asyncOperation = asyncOperation;
  321. this.continuationAction = null;
  322. }
  323. public bool IsCompleted => asyncOperation.isDone;
  324. public UnityEngine.Object GetResult()
  325. {
  326. if (continuationAction != null)
  327. {
  328. asyncOperation.completed -= continuationAction;
  329. continuationAction = null;
  330. var result = asyncOperation.asset;
  331. asyncOperation = null;
  332. return result;
  333. }
  334. else
  335. {
  336. var result = asyncOperation.asset;
  337. asyncOperation = null;
  338. return result;
  339. }
  340. }
  341. public void OnCompleted(Action continuation)
  342. {
  343. UnsafeOnCompleted(continuation);
  344. }
  345. public void UnsafeOnCompleted(Action continuation)
  346. {
  347. Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
  348. continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
  349. asyncOperation.completed += continuationAction;
  350. }
  351. }
  352. sealed class AssetBundleRequestConfiguredSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<AssetBundleRequestConfiguredSource>
  353. {
  354. static TaskPool<AssetBundleRequestConfiguredSource> pool;
  355. AssetBundleRequestConfiguredSource nextNode;
  356. public ref AssetBundleRequestConfiguredSource NextNode => ref nextNode;
  357. static AssetBundleRequestConfiguredSource()
  358. {
  359. TaskPool.RegisterSizeGetter(typeof(AssetBundleRequestConfiguredSource), () => pool.Size);
  360. }
  361. AssetBundleRequest asyncOperation;
  362. IProgress<float> progress;
  363. CancellationToken cancellationToken;
  364. UniTaskCompletionSourceCore<UnityEngine.Object> core;
  365. AssetBundleRequestConfiguredSource()
  366. {
  367. }
  368. public static IUniTaskSource<UnityEngine.Object> Create(AssetBundleRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
  369. {
  370. if (cancellationToken.IsCancellationRequested)
  371. {
  372. return AutoResetUniTaskCompletionSource<UnityEngine.Object>.CreateFromCanceled(cancellationToken, out token);
  373. }
  374. if (!pool.TryPop(out var result))
  375. {
  376. result = new AssetBundleRequestConfiguredSource();
  377. }
  378. result.asyncOperation = asyncOperation;
  379. result.progress = progress;
  380. result.cancellationToken = cancellationToken;
  381. TaskTracker.TrackActiveTask(result, 3);
  382. PlayerLoopHelper.AddAction(timing, result);
  383. token = result.core.Version;
  384. return result;
  385. }
  386. public UnityEngine.Object GetResult(short token)
  387. {
  388. try
  389. {
  390. return core.GetResult(token);
  391. }
  392. finally
  393. {
  394. TryReturn();
  395. }
  396. }
  397. void IUniTaskSource.GetResult(short token)
  398. {
  399. GetResult(token);
  400. }
  401. public UniTaskStatus GetStatus(short token)
  402. {
  403. return core.GetStatus(token);
  404. }
  405. public UniTaskStatus UnsafeGetStatus()
  406. {
  407. return core.UnsafeGetStatus();
  408. }
  409. public void OnCompleted(Action<object> continuation, object state, short token)
  410. {
  411. core.OnCompleted(continuation, state, token);
  412. }
  413. public bool MoveNext()
  414. {
  415. if (cancellationToken.IsCancellationRequested)
  416. {
  417. core.TrySetCanceled(cancellationToken);
  418. return false;
  419. }
  420. if (progress != null)
  421. {
  422. progress.Report(asyncOperation.progress);
  423. }
  424. if (asyncOperation.isDone)
  425. {
  426. core.TrySetResult(asyncOperation.asset);
  427. return false;
  428. }
  429. return true;
  430. }
  431. bool TryReturn()
  432. {
  433. TaskTracker.RemoveTracking(this);
  434. core.Reset();
  435. asyncOperation = default;
  436. progress = default;
  437. cancellationToken = default;
  438. return pool.TryPush(this);
  439. }
  440. }
  441. #endregion
  442. #endif
  443. #if UNITASK_ASSETBUNDLE_SUPPORT
  444. #region AssetBundleCreateRequest
  445. public static AssetBundleCreateRequestAwaiter GetAwaiter(this AssetBundleCreateRequest asyncOperation)
  446. {
  447. Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
  448. return new AssetBundleCreateRequestAwaiter(asyncOperation);
  449. }
  450. public static UniTask<AssetBundle> WithCancellation(this AssetBundleCreateRequest asyncOperation, CancellationToken cancellationToken)
  451. {
  452. return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
  453. }
  454. public static UniTask<AssetBundle> ToUniTask(this AssetBundleCreateRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
  455. {
  456. Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
  457. if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<AssetBundle>(cancellationToken);
  458. if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.assetBundle);
  459. return new UniTask<AssetBundle>(AssetBundleCreateRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
  460. }
  461. public struct AssetBundleCreateRequestAwaiter : ICriticalNotifyCompletion
  462. {
  463. AssetBundleCreateRequest asyncOperation;
  464. Action<AsyncOperation> continuationAction;
  465. public AssetBundleCreateRequestAwaiter(AssetBundleCreateRequest asyncOperation)
  466. {
  467. this.asyncOperation = asyncOperation;
  468. this.continuationAction = null;
  469. }
  470. public bool IsCompleted => asyncOperation.isDone;
  471. public AssetBundle GetResult()
  472. {
  473. if (continuationAction != null)
  474. {
  475. asyncOperation.completed -= continuationAction;
  476. continuationAction = null;
  477. var result = asyncOperation.assetBundle;
  478. asyncOperation = null;
  479. return result;
  480. }
  481. else
  482. {
  483. var result = asyncOperation.assetBundle;
  484. asyncOperation = null;
  485. return result;
  486. }
  487. }
  488. public void OnCompleted(Action continuation)
  489. {
  490. UnsafeOnCompleted(continuation);
  491. }
  492. public void UnsafeOnCompleted(Action continuation)
  493. {
  494. Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
  495. continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
  496. asyncOperation.completed += continuationAction;
  497. }
  498. }
  499. sealed class AssetBundleCreateRequestConfiguredSource : IUniTaskSource<AssetBundle>, IPlayerLoopItem, ITaskPoolNode<AssetBundleCreateRequestConfiguredSource>
  500. {
  501. static TaskPool<AssetBundleCreateRequestConfiguredSource> pool;
  502. AssetBundleCreateRequestConfiguredSource nextNode;
  503. public ref AssetBundleCreateRequestConfiguredSource NextNode => ref nextNode;
  504. static AssetBundleCreateRequestConfiguredSource()
  505. {
  506. TaskPool.RegisterSizeGetter(typeof(AssetBundleCreateRequestConfiguredSource), () => pool.Size);
  507. }
  508. AssetBundleCreateRequest asyncOperation;
  509. IProgress<float> progress;
  510. CancellationToken cancellationToken;
  511. UniTaskCompletionSourceCore<AssetBundle> core;
  512. AssetBundleCreateRequestConfiguredSource()
  513. {
  514. }
  515. public static IUniTaskSource<AssetBundle> Create(AssetBundleCreateRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
  516. {
  517. if (cancellationToken.IsCancellationRequested)
  518. {
  519. return AutoResetUniTaskCompletionSource<AssetBundle>.CreateFromCanceled(cancellationToken, out token);
  520. }
  521. if (!pool.TryPop(out var result))
  522. {
  523. result = new AssetBundleCreateRequestConfiguredSource();
  524. }
  525. result.asyncOperation = asyncOperation;
  526. result.progress = progress;
  527. result.cancellationToken = cancellationToken;
  528. TaskTracker.TrackActiveTask(result, 3);
  529. PlayerLoopHelper.AddAction(timing, result);
  530. token = result.core.Version;
  531. return result;
  532. }
  533. public AssetBundle GetResult(short token)
  534. {
  535. try
  536. {
  537. return core.GetResult(token);
  538. }
  539. finally
  540. {
  541. TryReturn();
  542. }
  543. }
  544. void IUniTaskSource.GetResult(short token)
  545. {
  546. GetResult(token);
  547. }
  548. public UniTaskStatus GetStatus(short token)
  549. {
  550. return core.GetStatus(token);
  551. }
  552. public UniTaskStatus UnsafeGetStatus()
  553. {
  554. return core.UnsafeGetStatus();
  555. }
  556. public void OnCompleted(Action<object> continuation, object state, short token)
  557. {
  558. core.OnCompleted(continuation, state, token);
  559. }
  560. public bool MoveNext()
  561. {
  562. if (cancellationToken.IsCancellationRequested)
  563. {
  564. core.TrySetCanceled(cancellationToken);
  565. return false;
  566. }
  567. if (progress != null)
  568. {
  569. progress.Report(asyncOperation.progress);
  570. }
  571. if (asyncOperation.isDone)
  572. {
  573. core.TrySetResult(asyncOperation.assetBundle);
  574. return false;
  575. }
  576. return true;
  577. }
  578. bool TryReturn()
  579. {
  580. TaskTracker.RemoveTracking(this);
  581. core.Reset();
  582. asyncOperation = default;
  583. progress = default;
  584. cancellationToken = default;
  585. return pool.TryPush(this);
  586. }
  587. }
  588. #endregion
  589. #endif
  590. #if ENABLE_UNITYWEBREQUEST && (!UNITY_2019_1_OR_NEWER || UNITASK_WEBREQUEST_SUPPORT)
  591. #region UnityWebRequestAsyncOperation
  592. public static UnityWebRequestAsyncOperationAwaiter GetAwaiter(this UnityWebRequestAsyncOperation asyncOperation)
  593. {
  594. Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
  595. return new UnityWebRequestAsyncOperationAwaiter(asyncOperation);
  596. }
  597. public static UniTask<UnityWebRequest> WithCancellation(this UnityWebRequestAsyncOperation asyncOperation, CancellationToken cancellationToken)
  598. {
  599. return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
  600. }
  601. public static UniTask<UnityWebRequest> ToUniTask(this UnityWebRequestAsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
  602. {
  603. Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
  604. if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityWebRequest>(cancellationToken);
  605. if (asyncOperation.isDone)
  606. {
  607. if (asyncOperation.webRequest.IsError())
  608. {
  609. return UniTask.FromException<UnityWebRequest>(new UnityWebRequestException(asyncOperation.webRequest));
  610. }
  611. return UniTask.FromResult(asyncOperation.webRequest);
  612. }
  613. return new UniTask<UnityWebRequest>(UnityWebRequestAsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
  614. }
  615. public struct UnityWebRequestAsyncOperationAwaiter : ICriticalNotifyCompletion
  616. {
  617. UnityWebRequestAsyncOperation asyncOperation;
  618. Action<AsyncOperation> continuationAction;
  619. public UnityWebRequestAsyncOperationAwaiter(UnityWebRequestAsyncOperation asyncOperation)
  620. {
  621. this.asyncOperation = asyncOperation;
  622. this.continuationAction = null;
  623. }
  624. public bool IsCompleted => asyncOperation.isDone;
  625. public UnityWebRequest GetResult()
  626. {
  627. if (continuationAction != null)
  628. {
  629. asyncOperation.completed -= continuationAction;
  630. continuationAction = null;
  631. var result = asyncOperation.webRequest;
  632. asyncOperation = null;
  633. if (result.IsError())
  634. {
  635. throw new UnityWebRequestException(result);
  636. }
  637. return result;
  638. }
  639. else
  640. {
  641. var result = asyncOperation.webRequest;
  642. asyncOperation = null;
  643. if (result.IsError())
  644. {
  645. throw new UnityWebRequestException(result);
  646. }
  647. return result;
  648. }
  649. }
  650. public void OnCompleted(Action continuation)
  651. {
  652. UnsafeOnCompleted(continuation);
  653. }
  654. public void UnsafeOnCompleted(Action continuation)
  655. {
  656. Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
  657. continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
  658. asyncOperation.completed += continuationAction;
  659. }
  660. }
  661. sealed class UnityWebRequestAsyncOperationConfiguredSource : IUniTaskSource<UnityWebRequest>, IPlayerLoopItem, ITaskPoolNode<UnityWebRequestAsyncOperationConfiguredSource>
  662. {
  663. static TaskPool<UnityWebRequestAsyncOperationConfiguredSource> pool;
  664. UnityWebRequestAsyncOperationConfiguredSource nextNode;
  665. public ref UnityWebRequestAsyncOperationConfiguredSource NextNode => ref nextNode;
  666. static UnityWebRequestAsyncOperationConfiguredSource()
  667. {
  668. TaskPool.RegisterSizeGetter(typeof(UnityWebRequestAsyncOperationConfiguredSource), () => pool.Size);
  669. }
  670. UnityWebRequestAsyncOperation asyncOperation;
  671. IProgress<float> progress;
  672. CancellationToken cancellationToken;
  673. UniTaskCompletionSourceCore<UnityWebRequest> core;
  674. UnityWebRequestAsyncOperationConfiguredSource()
  675. {
  676. }
  677. public static IUniTaskSource<UnityWebRequest> Create(UnityWebRequestAsyncOperation asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
  678. {
  679. if (cancellationToken.IsCancellationRequested)
  680. {
  681. return AutoResetUniTaskCompletionSource<UnityWebRequest>.CreateFromCanceled(cancellationToken, out token);
  682. }
  683. if (!pool.TryPop(out var result))
  684. {
  685. result = new UnityWebRequestAsyncOperationConfiguredSource();
  686. }
  687. result.asyncOperation = asyncOperation;
  688. result.progress = progress;
  689. result.cancellationToken = cancellationToken;
  690. TaskTracker.TrackActiveTask(result, 3);
  691. PlayerLoopHelper.AddAction(timing, result);
  692. token = result.core.Version;
  693. return result;
  694. }
  695. public UnityWebRequest GetResult(short token)
  696. {
  697. try
  698. {
  699. return core.GetResult(token);
  700. }
  701. finally
  702. {
  703. TryReturn();
  704. }
  705. }
  706. void IUniTaskSource.GetResult(short token)
  707. {
  708. GetResult(token);
  709. }
  710. public UniTaskStatus GetStatus(short token)
  711. {
  712. return core.GetStatus(token);
  713. }
  714. public UniTaskStatus UnsafeGetStatus()
  715. {
  716. return core.UnsafeGetStatus();
  717. }
  718. public void OnCompleted(Action<object> continuation, object state, short token)
  719. {
  720. core.OnCompleted(continuation, state, token);
  721. }
  722. public bool MoveNext()
  723. {
  724. if (cancellationToken.IsCancellationRequested)
  725. {
  726. asyncOperation.webRequest.Abort();
  727. core.TrySetCanceled(cancellationToken);
  728. return false;
  729. }
  730. if (progress != null)
  731. {
  732. progress.Report(asyncOperation.progress);
  733. }
  734. if (asyncOperation.isDone)
  735. {
  736. if (asyncOperation.webRequest.IsError())
  737. {
  738. core.TrySetException(new UnityWebRequestException(asyncOperation.webRequest));
  739. }
  740. else
  741. {
  742. core.TrySetResult(asyncOperation.webRequest);
  743. }
  744. return false;
  745. }
  746. return true;
  747. }
  748. bool TryReturn()
  749. {
  750. TaskTracker.RemoveTracking(this);
  751. core.Reset();
  752. asyncOperation = default;
  753. progress = default;
  754. cancellationToken = default;
  755. return pool.TryPush(this);
  756. }
  757. }
  758. #endregion
  759. #endif
  760. }
  761. }