Skip to content

Commit 5f0bcfb

Browse files
authored
Merge pull request #9870 from MaxWang-MS/async_fix
Fix some AsyncCoroutineRunner related issues
2 parents dddc522 + 783d9ba commit 5f0bcfb

File tree

2 files changed

+51
-10
lines changed

2 files changed

+51
-10
lines changed

Assets/MRTK/Core/Utilities/Async/AwaiterExtensions.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,14 @@ private static void RunOnUnityScheduler(Action action)
145145
}
146146
else
147147
{
148+
// Make sure there is a running instance of AsyncCoroutineRunner before calling AsyncCoroutineRunner.Post
149+
// If not warn the user. Note we cannot call AsyncCoroutineRunner.Instance here as that getter contains
150+
// calls to Unity functions that can only be run on the Unity thread
151+
if (!AsyncCoroutineRunner.IsInstanceRunning)
152+
{
153+
Debug.LogWarning("There is no active AsyncCoroutineRunner when an action is posted. Place a GameObject " +
154+
"at the root of the scene and attach the AsyncCoroutineRunner script to make it function properly.");
155+
}
148156
AsyncCoroutineRunner.Post(action);
149157
}
150158
}

Assets/MRTK/Core/Utilities/Async/Internal/AsyncCoroutineRunner.cs

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ internal sealed class AsyncCoroutineRunner : MonoBehaviour
4343
{
4444
private static AsyncCoroutineRunner instance;
4545

46+
private static bool isInstanceRunning = false;
47+
4648
private static readonly Queue<Action> Actions = new Queue<Action>();
4749

4850
internal static AsyncCoroutineRunner Instance
@@ -51,9 +53,18 @@ internal static AsyncCoroutineRunner Instance
5153
{
5254
if (instance == null)
5355
{
54-
instance = FindObjectOfType<AsyncCoroutineRunner>();
56+
AsyncCoroutineRunner[] instances = FindObjectsOfType<AsyncCoroutineRunner>();
57+
Debug.Assert(instances.Length <= 1, "[AsyncCoroutineRunner] There should only be one AsyncCoroutineRunner in the scene.");
58+
instance = instances.Length == 1 ? instances[0] : null;
59+
if (instance != null && !instance.enabled)
60+
{
61+
Debug.LogWarning("[AsyncCoroutineRunner] Found a disabled AsyncCoroutineRunner component. Enabling the component.");
62+
instance.enabled = true;
63+
}
5564
}
5665

66+
// FindObjectOfType() only search for objects attached to active GameObjects. The FindObjectOfType(bool includeInactive) variant is not available to Unity 2019.4 and earlier so cannot be used.
67+
// We instead search for GameObject called AsyncCoroutineRunner and see if it has the component attached.
5768
if (instance == null)
5869
{
5970
var instanceGameObject = GameObject.Find("AsyncCoroutineRunner");
@@ -64,22 +75,28 @@ internal static AsyncCoroutineRunner Instance
6475

6576
if (instance == null)
6677
{
67-
Debug.Log("[AsyncCoroutineRunner] Found GameObject but didn't have component");
68-
69-
if (Application.isPlaying)
78+
Debug.Log("[AsyncCoroutineRunner] Found a \"AsyncCoroutineRunner\" GameObject but didn't have the AsyncCoroutineRunner component attached. Attaching the script.");
79+
instance = instanceGameObject.AddComponent<AsyncCoroutineRunner>();
80+
}
81+
else
82+
{
83+
if (!instance.enabled)
7084
{
71-
Destroy(instanceGameObject);
85+
Debug.LogWarning("[AsyncCoroutineRunner] Found a disabled AsyncCoroutineRunner component. Enabling the component.");
86+
instance.enabled = true;
7287
}
73-
else
88+
if (!instanceGameObject.activeSelf)
7489
{
75-
DestroyImmediate(instanceGameObject);
90+
Debug.LogWarning("[AsyncCoroutineRunner] Found an AsyncCoroutineRunner attached to an inactive GameObject. Setting the GameObject active.");
91+
instanceGameObject.SetActive(true);
7692
}
7793
}
7894
}
7995
}
8096

8197
if (instance == null)
8298
{
99+
Debug.Log("[AsyncCoroutineRunner] There is no AsyncCoroutineRunner in the scene. Adding a GameObject with AsyncCoroutineRunner attached at the root of the scene.");
83100
instance = new GameObject("AsyncCoroutineRunner").AddComponent<AsyncCoroutineRunner>();
84101
}
85102

@@ -89,15 +106,14 @@ internal static AsyncCoroutineRunner Instance
89106
// This is ultimately to ensure that it persists across scene loads/unloads.
90107
if (instance.transform.parent != null)
91108
{
92-
Debug.LogWarning($"AsyncCoroutineRunner was found as a child of another GameObject {instance.transform.parent}, " +
109+
Debug.LogWarning($"[AsyncCoroutineRunner] AsyncCoroutineRunner was found as a child of another GameObject {instance.transform.parent}, " +
93110
"it must be a root object in the scene. Moving the AsyncCoroutineRunner to the root.");
94111
instance.transform.parent = null;
95112
}
96113

97114
#if !UNITY_EDITOR
98115
DontDestroyOnLoad(instance);
99116
#endif
100-
101117
return instance;
102118
}
103119
}
@@ -110,9 +126,12 @@ internal static void Post(Action task)
110126
}
111127
}
112128

129+
internal static bool IsInstanceRunning => isInstanceRunning;
130+
113131
private void Update()
114132
{
115-
Debug.Assert(Instance != null);
133+
Debug.Assert(Instance == this, "[AsyncCoroutineRunner] There should only be one AsyncCoroutineRunner in the scene.");
134+
isInstanceRunning = true;
116135

117136
int actionCount;
118137

@@ -133,5 +152,19 @@ private void Update()
133152
next();
134153
}
135154
}
155+
156+
private void OnDisable()
157+
{
158+
if (instance == this)
159+
{
160+
isInstanceRunning = false;
161+
}
162+
}
163+
164+
private void OnEnable()
165+
{
166+
Debug.Assert(Instance == this, "[AsyncCoroutineRunner] There should only be one AsyncCoroutineRunner in the scene.");
167+
isInstanceRunning = true;
168+
}
136169
}
137170
}

0 commit comments

Comments
 (0)