AsyncDestroyTrigger.cs 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
  2. using System.Threading;
  3. using UnityEngine;
  4. namespace Cysharp.Threading.Tasks.Triggers
  5. {
  6. public static partial class AsyncTriggerExtensions
  7. {
  8. public static AsyncDestroyTrigger GetAsyncDestroyTrigger(this GameObject gameObject)
  9. {
  10. return GetOrAddComponent<AsyncDestroyTrigger>(gameObject);
  11. }
  12. public static AsyncDestroyTrigger GetAsyncDestroyTrigger(this Component component)
  13. {
  14. return component.gameObject.GetAsyncDestroyTrigger();
  15. }
  16. }
  17. [DisallowMultipleComponent]
  18. public sealed class AsyncDestroyTrigger : MonoBehaviour
  19. {
  20. bool awakeCalled = false;
  21. bool called = false;
  22. CancellationTokenSource cancellationTokenSource;
  23. public CancellationToken CancellationToken
  24. {
  25. get
  26. {
  27. if (cancellationTokenSource == null)
  28. {
  29. cancellationTokenSource = new CancellationTokenSource();
  30. }
  31. if (!awakeCalled)
  32. {
  33. PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, new AwakeMonitor(this));
  34. }
  35. return cancellationTokenSource.Token;
  36. }
  37. }
  38. void Awake()
  39. {
  40. awakeCalled = true;
  41. }
  42. void OnDestroy()
  43. {
  44. called = true;
  45. cancellationTokenSource?.Cancel();
  46. cancellationTokenSource?.Dispose();
  47. }
  48. public UniTask OnDestroyAsync()
  49. {
  50. if (called) return UniTask.CompletedTask;
  51. var tcs = new UniTaskCompletionSource();
  52. // OnDestroy = Called Cancel.
  53. CancellationToken.RegisterWithoutCaptureExecutionContext(state =>
  54. {
  55. var tcs2 = (UniTaskCompletionSource)state;
  56. tcs2.TrySetResult();
  57. }, tcs);
  58. return tcs.Task;
  59. }
  60. class AwakeMonitor : IPlayerLoopItem
  61. {
  62. readonly AsyncDestroyTrigger trigger;
  63. public AwakeMonitor(AsyncDestroyTrigger trigger)
  64. {
  65. this.trigger = trigger;
  66. }
  67. public bool MoveNext()
  68. {
  69. if (trigger.called) return false;
  70. if (trigger == null)
  71. {
  72. trigger.OnDestroy();
  73. return false;
  74. }
  75. return true;
  76. }
  77. }
  78. }
  79. }