您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 

1216 行
45 KiB

  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. #if !UNITY_2023_1_OR_NEWER
  16. // from Unity2023.1.0a15, AsyncOperationAwaitableExtensions.GetAwaiter is defined in UnityEngine.
  17. public static AsyncOperationAwaiter GetAwaiter(this AsyncOperation asyncOperation)
  18. {
  19. Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
  20. return new AsyncOperationAwaiter(asyncOperation);
  21. }
  22. #endif
  23. public static UniTask WithCancellation(this AsyncOperation asyncOperation, CancellationToken cancellationToken)
  24. {
  25. return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
  26. }
  27. public static UniTask WithCancellation(this AsyncOperation asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
  28. {
  29. return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
  30. }
  31. public static UniTask ToUniTask(this AsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
  32. {
  33. Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
  34. if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled(cancellationToken);
  35. if (asyncOperation.isDone) return UniTask.CompletedTask;
  36. return new UniTask(AsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
  37. }
  38. public struct AsyncOperationAwaiter : ICriticalNotifyCompletion
  39. {
  40. AsyncOperation asyncOperation;
  41. Action<AsyncOperation> continuationAction;
  42. public AsyncOperationAwaiter(AsyncOperation asyncOperation)
  43. {
  44. this.asyncOperation = asyncOperation;
  45. this.continuationAction = null;
  46. }
  47. public bool IsCompleted => asyncOperation.isDone;
  48. public void GetResult()
  49. {
  50. if (continuationAction != null)
  51. {
  52. asyncOperation.completed -= continuationAction;
  53. continuationAction = null;
  54. asyncOperation = null;
  55. }
  56. else
  57. {
  58. asyncOperation = null;
  59. }
  60. }
  61. public void OnCompleted(Action continuation)
  62. {
  63. UnsafeOnCompleted(continuation);
  64. }
  65. public void UnsafeOnCompleted(Action continuation)
  66. {
  67. Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
  68. continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
  69. asyncOperation.completed += continuationAction;
  70. }
  71. }
  72. sealed class AsyncOperationConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationConfiguredSource>
  73. {
  74. static TaskPool<AsyncOperationConfiguredSource> pool;
  75. AsyncOperationConfiguredSource nextNode;
  76. public ref AsyncOperationConfiguredSource NextNode => ref nextNode;
  77. static AsyncOperationConfiguredSource()
  78. {
  79. TaskPool.RegisterSizeGetter(typeof(AsyncOperationConfiguredSource), () => pool.Size);
  80. }
  81. AsyncOperation asyncOperation;
  82. IProgress<float> progress;
  83. CancellationToken cancellationToken;
  84. CancellationTokenRegistration cancellationTokenRegistration;
  85. bool cancelImmediately;
  86. bool completed;
  87. UniTaskCompletionSourceCore<AsyncUnit> core;
  88. Action<AsyncOperation> continuationAction;
  89. AsyncOperationConfiguredSource()
  90. {
  91. continuationAction = Continuation;
  92. }
  93. public static IUniTaskSource Create(AsyncOperation asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
  94. {
  95. if (cancellationToken.IsCancellationRequested)
  96. {
  97. return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
  98. }
  99. if (!pool.TryPop(out var result))
  100. {
  101. result = new AsyncOperationConfiguredSource();
  102. }
  103. result.asyncOperation = asyncOperation;
  104. result.progress = progress;
  105. result.cancellationToken = cancellationToken;
  106. result.cancelImmediately = cancelImmediately;
  107. result.completed = false;
  108. asyncOperation.completed += result.continuationAction;
  109. if (cancelImmediately && cancellationToken.CanBeCanceled)
  110. {
  111. result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
  112. {
  113. var source = (AsyncOperationConfiguredSource)state;
  114. source.core.TrySetCanceled(source.cancellationToken);
  115. }, result);
  116. }
  117. TaskTracker.TrackActiveTask(result, 3);
  118. PlayerLoopHelper.AddAction(timing, result);
  119. token = result.core.Version;
  120. return result;
  121. }
  122. public void GetResult(short token)
  123. {
  124. try
  125. {
  126. core.GetResult(token);
  127. }
  128. finally
  129. {
  130. if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
  131. {
  132. TryReturn();
  133. }
  134. else
  135. {
  136. TaskTracker.RemoveTracking(this);
  137. }
  138. }
  139. }
  140. public UniTaskStatus GetStatus(short token)
  141. {
  142. return core.GetStatus(token);
  143. }
  144. public UniTaskStatus UnsafeGetStatus()
  145. {
  146. return core.UnsafeGetStatus();
  147. }
  148. public void OnCompleted(Action<object> continuation, object state, short token)
  149. {
  150. core.OnCompleted(continuation, state, token);
  151. }
  152. public bool MoveNext()
  153. {
  154. // Already completed
  155. if (completed || asyncOperation == null)
  156. {
  157. return false;
  158. }
  159. if (cancellationToken.IsCancellationRequested)
  160. {
  161. core.TrySetCanceled(cancellationToken);
  162. return false;
  163. }
  164. if (progress != null)
  165. {
  166. progress.Report(asyncOperation.progress);
  167. }
  168. if (asyncOperation.isDone)
  169. {
  170. core.TrySetResult(AsyncUnit.Default);
  171. return false;
  172. }
  173. return true;
  174. }
  175. bool TryReturn()
  176. {
  177. TaskTracker.RemoveTracking(this);
  178. core.Reset();
  179. asyncOperation.completed -= continuationAction;
  180. asyncOperation = default;
  181. progress = default;
  182. cancellationToken = default;
  183. cancellationTokenRegistration.Dispose();
  184. cancelImmediately = default;
  185. return pool.TryPush(this);
  186. }
  187. void Continuation(AsyncOperation _)
  188. {
  189. if (completed)
  190. {
  191. return;
  192. }
  193. completed = true;
  194. if (cancellationToken.IsCancellationRequested)
  195. {
  196. core.TrySetCanceled(cancellationToken);
  197. }
  198. else
  199. {
  200. core.TrySetResult(AsyncUnit.Default);
  201. }
  202. }
  203. }
  204. #endregion
  205. #region ResourceRequest
  206. public static ResourceRequestAwaiter GetAwaiter(this ResourceRequest asyncOperation)
  207. {
  208. Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
  209. return new ResourceRequestAwaiter(asyncOperation);
  210. }
  211. public static UniTask<UnityEngine.Object> WithCancellation(this ResourceRequest asyncOperation, CancellationToken cancellationToken)
  212. {
  213. return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
  214. }
  215. public static UniTask<UnityEngine.Object> WithCancellation(this ResourceRequest asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
  216. {
  217. return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
  218. }
  219. public static UniTask<UnityEngine.Object> ToUniTask(this ResourceRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
  220. {
  221. Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
  222. if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object>(cancellationToken);
  223. if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset);
  224. return new UniTask<UnityEngine.Object>(ResourceRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
  225. }
  226. public struct ResourceRequestAwaiter : ICriticalNotifyCompletion
  227. {
  228. ResourceRequest asyncOperation;
  229. Action<AsyncOperation> continuationAction;
  230. public ResourceRequestAwaiter(ResourceRequest asyncOperation)
  231. {
  232. this.asyncOperation = asyncOperation;
  233. this.continuationAction = null;
  234. }
  235. public bool IsCompleted => asyncOperation.isDone;
  236. public UnityEngine.Object GetResult()
  237. {
  238. if (continuationAction != null)
  239. {
  240. asyncOperation.completed -= continuationAction;
  241. continuationAction = null;
  242. var result = asyncOperation.asset;
  243. asyncOperation = null;
  244. return result;
  245. }
  246. else
  247. {
  248. var result = asyncOperation.asset;
  249. asyncOperation = null;
  250. return result;
  251. }
  252. }
  253. public void OnCompleted(Action continuation)
  254. {
  255. UnsafeOnCompleted(continuation);
  256. }
  257. public void UnsafeOnCompleted(Action continuation)
  258. {
  259. Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
  260. continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
  261. asyncOperation.completed += continuationAction;
  262. }
  263. }
  264. sealed class ResourceRequestConfiguredSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<ResourceRequestConfiguredSource>
  265. {
  266. static TaskPool<ResourceRequestConfiguredSource> pool;
  267. ResourceRequestConfiguredSource nextNode;
  268. public ref ResourceRequestConfiguredSource NextNode => ref nextNode;
  269. static ResourceRequestConfiguredSource()
  270. {
  271. TaskPool.RegisterSizeGetter(typeof(ResourceRequestConfiguredSource), () => pool.Size);
  272. }
  273. ResourceRequest asyncOperation;
  274. IProgress<float> progress;
  275. CancellationToken cancellationToken;
  276. CancellationTokenRegistration cancellationTokenRegistration;
  277. bool cancelImmediately;
  278. bool completed;
  279. UniTaskCompletionSourceCore<UnityEngine.Object> core;
  280. Action<AsyncOperation> continuationAction;
  281. ResourceRequestConfiguredSource()
  282. {
  283. continuationAction = Continuation;
  284. }
  285. public static IUniTaskSource<UnityEngine.Object> Create(ResourceRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
  286. {
  287. if (cancellationToken.IsCancellationRequested)
  288. {
  289. return AutoResetUniTaskCompletionSource<UnityEngine.Object>.CreateFromCanceled(cancellationToken, out token);
  290. }
  291. if (!pool.TryPop(out var result))
  292. {
  293. result = new ResourceRequestConfiguredSource();
  294. }
  295. result.asyncOperation = asyncOperation;
  296. result.progress = progress;
  297. result.cancellationToken = cancellationToken;
  298. result.cancelImmediately = cancelImmediately;
  299. result.completed = false;
  300. asyncOperation.completed += result.continuationAction;
  301. if (cancelImmediately && cancellationToken.CanBeCanceled)
  302. {
  303. result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
  304. {
  305. var source = (ResourceRequestConfiguredSource)state;
  306. source.core.TrySetCanceled(source.cancellationToken);
  307. }, result);
  308. }
  309. TaskTracker.TrackActiveTask(result, 3);
  310. PlayerLoopHelper.AddAction(timing, result);
  311. token = result.core.Version;
  312. return result;
  313. }
  314. public UnityEngine.Object GetResult(short token)
  315. {
  316. try
  317. {
  318. return core.GetResult(token);
  319. }
  320. finally
  321. {
  322. if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
  323. {
  324. TryReturn();
  325. }
  326. else
  327. {
  328. TaskTracker.RemoveTracking(this);
  329. }
  330. }
  331. }
  332. void IUniTaskSource.GetResult(short token)
  333. {
  334. GetResult(token);
  335. }
  336. public UniTaskStatus GetStatus(short token)
  337. {
  338. return core.GetStatus(token);
  339. }
  340. public UniTaskStatus UnsafeGetStatus()
  341. {
  342. return core.UnsafeGetStatus();
  343. }
  344. public void OnCompleted(Action<object> continuation, object state, short token)
  345. {
  346. core.OnCompleted(continuation, state, token);
  347. }
  348. public bool MoveNext()
  349. {
  350. // Already completed
  351. if (completed || asyncOperation == null)
  352. {
  353. return false;
  354. }
  355. if (cancellationToken.IsCancellationRequested)
  356. {
  357. core.TrySetCanceled(cancellationToken);
  358. return false;
  359. }
  360. if (progress != null)
  361. {
  362. progress.Report(asyncOperation.progress);
  363. }
  364. if (asyncOperation.isDone)
  365. {
  366. core.TrySetResult(asyncOperation.asset);
  367. return false;
  368. }
  369. return true;
  370. }
  371. bool TryReturn()
  372. {
  373. TaskTracker.RemoveTracking(this);
  374. core.Reset();
  375. asyncOperation.completed -= continuationAction;
  376. asyncOperation = default;
  377. progress = default;
  378. cancellationToken = default;
  379. cancellationTokenRegistration.Dispose();
  380. cancelImmediately = default;
  381. return pool.TryPush(this);
  382. }
  383. void Continuation(AsyncOperation _)
  384. {
  385. if (completed)
  386. {
  387. return;
  388. }
  389. completed = true;
  390. if (cancellationToken.IsCancellationRequested)
  391. {
  392. core.TrySetCanceled(cancellationToken);
  393. }
  394. else
  395. {
  396. core.TrySetResult(asyncOperation.asset);
  397. }
  398. }
  399. }
  400. #endregion
  401. #if UNITASK_ASSETBUNDLE_SUPPORT
  402. #region AssetBundleRequest
  403. public static AssetBundleRequestAwaiter GetAwaiter(this AssetBundleRequest asyncOperation)
  404. {
  405. Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
  406. return new AssetBundleRequestAwaiter(asyncOperation);
  407. }
  408. public static UniTask<UnityEngine.Object> WithCancellation(this AssetBundleRequest asyncOperation, CancellationToken cancellationToken)
  409. {
  410. return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
  411. }
  412. public static UniTask<UnityEngine.Object> WithCancellation(this AssetBundleRequest asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
  413. {
  414. return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
  415. }
  416. public static UniTask<UnityEngine.Object> ToUniTask(this AssetBundleRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
  417. {
  418. Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
  419. if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object>(cancellationToken);
  420. if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset);
  421. return new UniTask<UnityEngine.Object>(AssetBundleRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
  422. }
  423. public struct AssetBundleRequestAwaiter : ICriticalNotifyCompletion
  424. {
  425. AssetBundleRequest asyncOperation;
  426. Action<AsyncOperation> continuationAction;
  427. public AssetBundleRequestAwaiter(AssetBundleRequest asyncOperation)
  428. {
  429. this.asyncOperation = asyncOperation;
  430. this.continuationAction = null;
  431. }
  432. public bool IsCompleted => asyncOperation.isDone;
  433. public UnityEngine.Object GetResult()
  434. {
  435. if (continuationAction != null)
  436. {
  437. asyncOperation.completed -= continuationAction;
  438. continuationAction = null;
  439. var result = asyncOperation.asset;
  440. asyncOperation = null;
  441. return result;
  442. }
  443. else
  444. {
  445. var result = asyncOperation.asset;
  446. asyncOperation = null;
  447. return result;
  448. }
  449. }
  450. public void OnCompleted(Action continuation)
  451. {
  452. UnsafeOnCompleted(continuation);
  453. }
  454. public void UnsafeOnCompleted(Action continuation)
  455. {
  456. Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
  457. continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
  458. asyncOperation.completed += continuationAction;
  459. }
  460. }
  461. sealed class AssetBundleRequestConfiguredSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<AssetBundleRequestConfiguredSource>
  462. {
  463. static TaskPool<AssetBundleRequestConfiguredSource> pool;
  464. AssetBundleRequestConfiguredSource nextNode;
  465. public ref AssetBundleRequestConfiguredSource NextNode => ref nextNode;
  466. static AssetBundleRequestConfiguredSource()
  467. {
  468. TaskPool.RegisterSizeGetter(typeof(AssetBundleRequestConfiguredSource), () => pool.Size);
  469. }
  470. AssetBundleRequest asyncOperation;
  471. IProgress<float> progress;
  472. CancellationToken cancellationToken;
  473. CancellationTokenRegistration cancellationTokenRegistration;
  474. bool cancelImmediately;
  475. bool completed;
  476. UniTaskCompletionSourceCore<UnityEngine.Object> core;
  477. Action<AsyncOperation> continuationAction;
  478. AssetBundleRequestConfiguredSource()
  479. {
  480. continuationAction = Continuation;
  481. }
  482. public static IUniTaskSource<UnityEngine.Object> Create(AssetBundleRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
  483. {
  484. if (cancellationToken.IsCancellationRequested)
  485. {
  486. return AutoResetUniTaskCompletionSource<UnityEngine.Object>.CreateFromCanceled(cancellationToken, out token);
  487. }
  488. if (!pool.TryPop(out var result))
  489. {
  490. result = new AssetBundleRequestConfiguredSource();
  491. }
  492. result.asyncOperation = asyncOperation;
  493. result.progress = progress;
  494. result.cancellationToken = cancellationToken;
  495. result.cancelImmediately = cancelImmediately;
  496. result.completed = false;
  497. asyncOperation.completed += result.continuationAction;
  498. if (cancelImmediately && cancellationToken.CanBeCanceled)
  499. {
  500. result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
  501. {
  502. var source = (AssetBundleRequestConfiguredSource)state;
  503. source.core.TrySetCanceled(source.cancellationToken);
  504. }, result);
  505. }
  506. TaskTracker.TrackActiveTask(result, 3);
  507. PlayerLoopHelper.AddAction(timing, result);
  508. token = result.core.Version;
  509. return result;
  510. }
  511. public UnityEngine.Object GetResult(short token)
  512. {
  513. try
  514. {
  515. return core.GetResult(token);
  516. }
  517. finally
  518. {
  519. if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
  520. {
  521. TryReturn();
  522. }
  523. else
  524. {
  525. TaskTracker.RemoveTracking(this);
  526. }
  527. }
  528. }
  529. void IUniTaskSource.GetResult(short token)
  530. {
  531. GetResult(token);
  532. }
  533. public UniTaskStatus GetStatus(short token)
  534. {
  535. return core.GetStatus(token);
  536. }
  537. public UniTaskStatus UnsafeGetStatus()
  538. {
  539. return core.UnsafeGetStatus();
  540. }
  541. public void OnCompleted(Action<object> continuation, object state, short token)
  542. {
  543. core.OnCompleted(continuation, state, token);
  544. }
  545. public bool MoveNext()
  546. {
  547. // Already completed
  548. if (completed || asyncOperation == null)
  549. {
  550. return false;
  551. }
  552. if (cancellationToken.IsCancellationRequested)
  553. {
  554. core.TrySetCanceled(cancellationToken);
  555. return false;
  556. }
  557. if (progress != null)
  558. {
  559. progress.Report(asyncOperation.progress);
  560. }
  561. if (asyncOperation.isDone)
  562. {
  563. core.TrySetResult(asyncOperation.asset);
  564. return false;
  565. }
  566. return true;
  567. }
  568. bool TryReturn()
  569. {
  570. TaskTracker.RemoveTracking(this);
  571. core.Reset();
  572. asyncOperation.completed -= continuationAction;
  573. asyncOperation = default;
  574. progress = default;
  575. cancellationToken = default;
  576. cancellationTokenRegistration.Dispose();
  577. cancelImmediately = default;
  578. return pool.TryPush(this);
  579. }
  580. void Continuation(AsyncOperation _)
  581. {
  582. if (completed)
  583. {
  584. return;
  585. }
  586. completed = true;
  587. if (cancellationToken.IsCancellationRequested)
  588. {
  589. core.TrySetCanceled(cancellationToken);
  590. }
  591. else
  592. {
  593. core.TrySetResult(asyncOperation.asset);
  594. }
  595. }
  596. }
  597. #endregion
  598. #endif
  599. #if UNITASK_ASSETBUNDLE_SUPPORT
  600. #region AssetBundleCreateRequest
  601. public static AssetBundleCreateRequestAwaiter GetAwaiter(this AssetBundleCreateRequest asyncOperation)
  602. {
  603. Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
  604. return new AssetBundleCreateRequestAwaiter(asyncOperation);
  605. }
  606. public static UniTask<AssetBundle> WithCancellation(this AssetBundleCreateRequest asyncOperation, CancellationToken cancellationToken)
  607. {
  608. return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
  609. }
  610. public static UniTask<AssetBundle> WithCancellation(this AssetBundleCreateRequest asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
  611. {
  612. return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
  613. }
  614. public static UniTask<AssetBundle> ToUniTask(this AssetBundleCreateRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
  615. {
  616. Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
  617. if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<AssetBundle>(cancellationToken);
  618. if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.assetBundle);
  619. return new UniTask<AssetBundle>(AssetBundleCreateRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
  620. }
  621. public struct AssetBundleCreateRequestAwaiter : ICriticalNotifyCompletion
  622. {
  623. AssetBundleCreateRequest asyncOperation;
  624. Action<AsyncOperation> continuationAction;
  625. public AssetBundleCreateRequestAwaiter(AssetBundleCreateRequest asyncOperation)
  626. {
  627. this.asyncOperation = asyncOperation;
  628. this.continuationAction = null;
  629. }
  630. public bool IsCompleted => asyncOperation.isDone;
  631. public AssetBundle GetResult()
  632. {
  633. if (continuationAction != null)
  634. {
  635. asyncOperation.completed -= continuationAction;
  636. continuationAction = null;
  637. var result = asyncOperation.assetBundle;
  638. asyncOperation = null;
  639. return result;
  640. }
  641. else
  642. {
  643. var result = asyncOperation.assetBundle;
  644. asyncOperation = null;
  645. return result;
  646. }
  647. }
  648. public void OnCompleted(Action continuation)
  649. {
  650. UnsafeOnCompleted(continuation);
  651. }
  652. public void UnsafeOnCompleted(Action continuation)
  653. {
  654. Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
  655. continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
  656. asyncOperation.completed += continuationAction;
  657. }
  658. }
  659. sealed class AssetBundleCreateRequestConfiguredSource : IUniTaskSource<AssetBundle>, IPlayerLoopItem, ITaskPoolNode<AssetBundleCreateRequestConfiguredSource>
  660. {
  661. static TaskPool<AssetBundleCreateRequestConfiguredSource> pool;
  662. AssetBundleCreateRequestConfiguredSource nextNode;
  663. public ref AssetBundleCreateRequestConfiguredSource NextNode => ref nextNode;
  664. static AssetBundleCreateRequestConfiguredSource()
  665. {
  666. TaskPool.RegisterSizeGetter(typeof(AssetBundleCreateRequestConfiguredSource), () => pool.Size);
  667. }
  668. AssetBundleCreateRequest asyncOperation;
  669. IProgress<float> progress;
  670. CancellationToken cancellationToken;
  671. CancellationTokenRegistration cancellationTokenRegistration;
  672. bool cancelImmediately;
  673. bool completed;
  674. UniTaskCompletionSourceCore<AssetBundle> core;
  675. Action<AsyncOperation> continuationAction;
  676. AssetBundleCreateRequestConfiguredSource()
  677. {
  678. continuationAction = Continuation;
  679. }
  680. public static IUniTaskSource<AssetBundle> Create(AssetBundleCreateRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
  681. {
  682. if (cancellationToken.IsCancellationRequested)
  683. {
  684. return AutoResetUniTaskCompletionSource<AssetBundle>.CreateFromCanceled(cancellationToken, out token);
  685. }
  686. if (!pool.TryPop(out var result))
  687. {
  688. result = new AssetBundleCreateRequestConfiguredSource();
  689. }
  690. result.asyncOperation = asyncOperation;
  691. result.progress = progress;
  692. result.cancellationToken = cancellationToken;
  693. result.cancelImmediately = cancelImmediately;
  694. result.completed = false;
  695. asyncOperation.completed += result.continuationAction;
  696. if (cancelImmediately && cancellationToken.CanBeCanceled)
  697. {
  698. result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
  699. {
  700. var source = (AssetBundleCreateRequestConfiguredSource)state;
  701. source.core.TrySetCanceled(source.cancellationToken);
  702. }, result);
  703. }
  704. TaskTracker.TrackActiveTask(result, 3);
  705. PlayerLoopHelper.AddAction(timing, result);
  706. token = result.core.Version;
  707. return result;
  708. }
  709. public AssetBundle GetResult(short token)
  710. {
  711. try
  712. {
  713. return core.GetResult(token);
  714. }
  715. finally
  716. {
  717. if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
  718. {
  719. TryReturn();
  720. }
  721. else
  722. {
  723. TaskTracker.RemoveTracking(this);
  724. }
  725. }
  726. }
  727. void IUniTaskSource.GetResult(short token)
  728. {
  729. GetResult(token);
  730. }
  731. public UniTaskStatus GetStatus(short token)
  732. {
  733. return core.GetStatus(token);
  734. }
  735. public UniTaskStatus UnsafeGetStatus()
  736. {
  737. return core.UnsafeGetStatus();
  738. }
  739. public void OnCompleted(Action<object> continuation, object state, short token)
  740. {
  741. core.OnCompleted(continuation, state, token);
  742. }
  743. public bool MoveNext()
  744. {
  745. // Already completed
  746. if (completed || asyncOperation == null)
  747. {
  748. return false;
  749. }
  750. if (cancellationToken.IsCancellationRequested)
  751. {
  752. core.TrySetCanceled(cancellationToken);
  753. return false;
  754. }
  755. if (progress != null)
  756. {
  757. progress.Report(asyncOperation.progress);
  758. }
  759. if (asyncOperation.isDone)
  760. {
  761. core.TrySetResult(asyncOperation.assetBundle);
  762. return false;
  763. }
  764. return true;
  765. }
  766. bool TryReturn()
  767. {
  768. TaskTracker.RemoveTracking(this);
  769. core.Reset();
  770. asyncOperation.completed -= continuationAction;
  771. asyncOperation = default;
  772. progress = default;
  773. cancellationToken = default;
  774. cancellationTokenRegistration.Dispose();
  775. cancelImmediately = default;
  776. return pool.TryPush(this);
  777. }
  778. void Continuation(AsyncOperation _)
  779. {
  780. if (completed)
  781. {
  782. return;
  783. }
  784. completed = true;
  785. if (cancellationToken.IsCancellationRequested)
  786. {
  787. core.TrySetCanceled(cancellationToken);
  788. }
  789. else
  790. {
  791. core.TrySetResult(asyncOperation.assetBundle);
  792. }
  793. }
  794. }
  795. #endregion
  796. #endif
  797. #if ENABLE_UNITYWEBREQUEST && (!UNITY_2019_1_OR_NEWER || UNITASK_WEBREQUEST_SUPPORT)
  798. #region UnityWebRequestAsyncOperation
  799. public static UnityWebRequestAsyncOperationAwaiter GetAwaiter(this UnityWebRequestAsyncOperation asyncOperation)
  800. {
  801. Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
  802. return new UnityWebRequestAsyncOperationAwaiter(asyncOperation);
  803. }
  804. public static UniTask<UnityWebRequest> WithCancellation(this UnityWebRequestAsyncOperation asyncOperation, CancellationToken cancellationToken)
  805. {
  806. return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
  807. }
  808. public static UniTask<UnityWebRequest> WithCancellation(this UnityWebRequestAsyncOperation asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
  809. {
  810. return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
  811. }
  812. public static UniTask<UnityWebRequest> ToUniTask(this UnityWebRequestAsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
  813. {
  814. Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
  815. if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityWebRequest>(cancellationToken);
  816. if (asyncOperation.isDone)
  817. {
  818. if (asyncOperation.webRequest.IsError())
  819. {
  820. return UniTask.FromException<UnityWebRequest>(new UnityWebRequestException(asyncOperation.webRequest));
  821. }
  822. return UniTask.FromResult(asyncOperation.webRequest);
  823. }
  824. return new UniTask<UnityWebRequest>(UnityWebRequestAsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
  825. }
  826. public struct UnityWebRequestAsyncOperationAwaiter : ICriticalNotifyCompletion
  827. {
  828. UnityWebRequestAsyncOperation asyncOperation;
  829. Action<AsyncOperation> continuationAction;
  830. public UnityWebRequestAsyncOperationAwaiter(UnityWebRequestAsyncOperation asyncOperation)
  831. {
  832. this.asyncOperation = asyncOperation;
  833. this.continuationAction = null;
  834. }
  835. public bool IsCompleted => asyncOperation.isDone;
  836. public UnityWebRequest GetResult()
  837. {
  838. if (continuationAction != null)
  839. {
  840. asyncOperation.completed -= continuationAction;
  841. continuationAction = null;
  842. var result = asyncOperation.webRequest;
  843. asyncOperation = null;
  844. if (result.IsError())
  845. {
  846. throw new UnityWebRequestException(result);
  847. }
  848. return result;
  849. }
  850. else
  851. {
  852. var result = asyncOperation.webRequest;
  853. asyncOperation = null;
  854. if (result.IsError())
  855. {
  856. throw new UnityWebRequestException(result);
  857. }
  858. return result;
  859. }
  860. }
  861. public void OnCompleted(Action continuation)
  862. {
  863. UnsafeOnCompleted(continuation);
  864. }
  865. public void UnsafeOnCompleted(Action continuation)
  866. {
  867. Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
  868. continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
  869. asyncOperation.completed += continuationAction;
  870. }
  871. }
  872. sealed class UnityWebRequestAsyncOperationConfiguredSource : IUniTaskSource<UnityWebRequest>, IPlayerLoopItem, ITaskPoolNode<UnityWebRequestAsyncOperationConfiguredSource>
  873. {
  874. static TaskPool<UnityWebRequestAsyncOperationConfiguredSource> pool;
  875. UnityWebRequestAsyncOperationConfiguredSource nextNode;
  876. public ref UnityWebRequestAsyncOperationConfiguredSource NextNode => ref nextNode;
  877. static UnityWebRequestAsyncOperationConfiguredSource()
  878. {
  879. TaskPool.RegisterSizeGetter(typeof(UnityWebRequestAsyncOperationConfiguredSource), () => pool.Size);
  880. }
  881. UnityWebRequestAsyncOperation asyncOperation;
  882. IProgress<float> progress;
  883. CancellationToken cancellationToken;
  884. CancellationTokenRegistration cancellationTokenRegistration;
  885. bool cancelImmediately;
  886. bool completed;
  887. UniTaskCompletionSourceCore<UnityWebRequest> core;
  888. Action<AsyncOperation> continuationAction;
  889. UnityWebRequestAsyncOperationConfiguredSource()
  890. {
  891. continuationAction = Continuation;
  892. }
  893. public static IUniTaskSource<UnityWebRequest> Create(UnityWebRequestAsyncOperation asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
  894. {
  895. if (cancellationToken.IsCancellationRequested)
  896. {
  897. return AutoResetUniTaskCompletionSource<UnityWebRequest>.CreateFromCanceled(cancellationToken, out token);
  898. }
  899. if (!pool.TryPop(out var result))
  900. {
  901. result = new UnityWebRequestAsyncOperationConfiguredSource();
  902. }
  903. result.asyncOperation = asyncOperation;
  904. result.progress = progress;
  905. result.cancellationToken = cancellationToken;
  906. result.cancelImmediately = cancelImmediately;
  907. result.completed = false;
  908. asyncOperation.completed += result.continuationAction;
  909. if (cancelImmediately && cancellationToken.CanBeCanceled)
  910. {
  911. result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
  912. {
  913. var source = (UnityWebRequestAsyncOperationConfiguredSource)state;
  914. source.asyncOperation.webRequest.Abort();
  915. source.core.TrySetCanceled(source.cancellationToken);
  916. }, result);
  917. }
  918. TaskTracker.TrackActiveTask(result, 3);
  919. PlayerLoopHelper.AddAction(timing, result);
  920. token = result.core.Version;
  921. return result;
  922. }
  923. public UnityWebRequest GetResult(short token)
  924. {
  925. try
  926. {
  927. return core.GetResult(token);
  928. }
  929. finally
  930. {
  931. if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
  932. {
  933. TryReturn();
  934. }
  935. else
  936. {
  937. TaskTracker.RemoveTracking(this);
  938. }
  939. }
  940. }
  941. void IUniTaskSource.GetResult(short token)
  942. {
  943. GetResult(token);
  944. }
  945. public UniTaskStatus GetStatus(short token)
  946. {
  947. return core.GetStatus(token);
  948. }
  949. public UniTaskStatus UnsafeGetStatus()
  950. {
  951. return core.UnsafeGetStatus();
  952. }
  953. public void OnCompleted(Action<object> continuation, object state, short token)
  954. {
  955. core.OnCompleted(continuation, state, token);
  956. }
  957. public bool MoveNext()
  958. {
  959. // Already completed
  960. if (completed || asyncOperation == null)
  961. {
  962. return false;
  963. }
  964. if (cancellationToken.IsCancellationRequested)
  965. {
  966. asyncOperation.webRequest.Abort();
  967. core.TrySetCanceled(cancellationToken);
  968. return false;
  969. }
  970. if (progress != null)
  971. {
  972. progress.Report(asyncOperation.progress);
  973. }
  974. if (asyncOperation.isDone)
  975. {
  976. if (asyncOperation.webRequest.IsError())
  977. {
  978. core.TrySetException(new UnityWebRequestException(asyncOperation.webRequest));
  979. }
  980. else
  981. {
  982. core.TrySetResult(asyncOperation.webRequest);
  983. }
  984. return false;
  985. }
  986. return true;
  987. }
  988. bool TryReturn()
  989. {
  990. TaskTracker.RemoveTracking(this);
  991. core.Reset();
  992. asyncOperation.completed -= continuationAction;
  993. asyncOperation = default;
  994. progress = default;
  995. cancellationToken = default;
  996. cancellationTokenRegistration.Dispose();
  997. cancelImmediately = default;
  998. return pool.TryPush(this);
  999. }
  1000. void Continuation(AsyncOperation _)
  1001. {
  1002. if (completed)
  1003. {
  1004. return;
  1005. }
  1006. completed = true;
  1007. if (cancellationToken.IsCancellationRequested)
  1008. {
  1009. core.TrySetCanceled(cancellationToken);
  1010. }
  1011. else if (asyncOperation.webRequest.IsError())
  1012. {
  1013. core.TrySetException(new UnityWebRequestException(asyncOperation.webRequest));
  1014. }
  1015. else
  1016. {
  1017. core.TrySetResult(asyncOperation.webRequest);
  1018. }
  1019. }
  1020. }
  1021. #endregion
  1022. #endif
  1023. }
  1024. }