Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 

141 wiersze
4.7 KiB

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. namespace SUISS.Cloud
  6. {
  7. public class CloudRequestRunner
  8. {
  9. private class CoroutineWapper : CustomYieldInstruction
  10. {
  11. private bool _isRunning;
  12. private IEnumerator _innerRoutine;
  13. private CloudRequestRunner _scheduler;
  14. private MonoBehaviour _executor;
  15. public override bool keepWaiting => _isRunning;
  16. public CoroutineWapper(IEnumerator routine, CloudRequestRunner scheduler)
  17. {
  18. _scheduler = scheduler;
  19. _executor = _scheduler.Executor;
  20. _innerRoutine = routine;
  21. if (_executor != null)
  22. {
  23. _isRunning = true;
  24. _executor.StartCoroutine(Routine(routine));
  25. }
  26. }
  27. private IEnumerator Routine(IEnumerator routine)
  28. {
  29. while (routine.MoveNext())
  30. {
  31. object yielded = routine.Current;
  32. if (yielded != null && !_scheduler.IsSupportedYieldable(yielded))
  33. {
  34. UnityEngine.Debug.LogWarning(string.Format("The coroutine '{0}' yielded '{1}' which is not supported by '{2}'!", _innerRoutine, yielded ?? "null", _scheduler));
  35. }
  36. yield return yielded;
  37. }
  38. _scheduler.OnRoutineCompleted(_innerRoutine);
  39. _isRunning = false;
  40. }
  41. }
  42. private class CloudRequestRunnerMonoBehaviour : MonoBehaviour
  43. {
  44. }
  45. private HashSet<IEnumerator> _runningRoutines = new HashSet<IEnumerator>();
  46. private MonoBehaviour _executor;
  47. private string _executorName;
  48. private static CloudRequestRunner _instance;
  49. private MonoBehaviour Executor
  50. {
  51. get
  52. {
  53. if (_executor == null)
  54. {
  55. UnityEngine.Debug.LogError($"{this} is going to create a second GameObject to run coroutines! (Is the app quitting?) Any coroutines running before this may not have been completed! I hope you never see this error! :(");
  56. CreateScheduleExecutor();
  57. _runningRoutines.Clear();
  58. }
  59. return _executor;
  60. }
  61. }
  62. private CloudRequestRunner()
  63. {
  64. _executorName = $"__CloudRequestRunner{UnityEngine.Random.Range(1000, 9999)}";
  65. CreateScheduleExecutor();
  66. }
  67. public static CustomYieldInstruction StartCoroutine(IEnumerator routine)
  68. {
  69. if (_instance == null)
  70. {
  71. _instance = new CloudRequestRunner();
  72. }
  73. return _instance.StartRoutine(routine);
  74. }
  75. private CustomYieldInstruction StartRoutine(IEnumerator routine)
  76. {
  77. if (_executor == null)
  78. {
  79. CreateScheduleExecutor();
  80. }
  81. if (_executor != null)
  82. {
  83. if (_runningRoutines.Contains(routine))
  84. {
  85. throw new Exception($"You are calling StartRoutine on a routine '{routine}' that was already started.");
  86. }
  87. _runningRoutines.Add(routine);
  88. return new CoroutineWapper(routine, this);
  89. }
  90. UnityEngine.Debug.LogError($"The schedule executor backing this scheduler is null! Can't start {routine}");
  91. return null;
  92. }
  93. private bool IsSupportedYieldable(object yieldable)
  94. {
  95. return yieldable == null || yieldable is WWW || yieldable is YieldInstruction || yieldable is CustomYieldInstruction;
  96. }
  97. private void CreateScheduleExecutor()
  98. {
  99. if (_executor == null)
  100. {
  101. GameObject gameObject = GameObject.Find(_executorName);
  102. if (gameObject == null)
  103. {
  104. gameObject = new GameObject();
  105. gameObject.name = _executorName;
  106. UnityEngine.Object.DontDestroyOnLoad(gameObject);
  107. }
  108. _executor = gameObject.GetComponent<MonoBehaviour>();
  109. if (_executor == null)
  110. {
  111. _executor = gameObject.AddComponent<CloudRequestRunnerMonoBehaviour>();
  112. }
  113. }
  114. }
  115. private void OnRoutineCompleted(IEnumerator routine)
  116. {
  117. _runningRoutines.Remove(routine);
  118. }
  119. }
  120. }