modesttree / Unity3dAsyncAwaitUtil

A bunch of code to make using async-await easier in Unity3D
MIT License
454 stars 119 forks source link

Cannot use for Editor unit testing, as SyncContextUtil.Install is not called except at runtime #9

Open jokigenki opened 6 years ago

jokigenki commented 6 years ago

I hacked this by making SyncContextUtil.Install public and calling it in my tests SetUp method, but I don't know if there's a better way?

svermeulen commented 6 years ago

We should probably change it to use the [InitializeOnLoad] instead of [RuntimeInitializeOnLoad]. But I'd have to test it to be sure that works correctly

svermeulen commented 6 years ago

Since I'm not sure that runs before awake. But we could use both attributes in that case too

StephenHodgson commented 6 years ago

Unity also doesn't support executing the async in the editor as well, you'll also need a pump.

See https://forum.unity.com/threads/async-await-in-editor-script.481276/

StephenHodgson commented 6 years ago

Here's an modified version of @svermeulen's project that I included in another project. I've been meaning to open pull requests to add this stuff back but I've been pretty busy.

#if UNITY_EDITOR
        private static System.Reflection.MethodInfo executionMethod;

        /// <summary>
        /// HACK: makes Unity Editor execute continuations in edit mode.
        /// </summary>
        private static void ExecuteContinuations()
        {
            if (UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode)
            {
                return;
            }

            var context = SynchronizationContext.Current;

            if (executionMethod == null)
            {
                executionMethod = context.GetType().GetMethod("Exec", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
            }

            executionMethod?.Invoke(context, null);
        }

        [UnityEditor.InitializeOnLoadMethod]
#endif
        [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
        private static void Initialize()
        {
#if UNITY_EDITOR
            UnityEditor.EditorApplication.update += ExecuteContinuations;
#endif
            UnitySynchronizationContext = SynchronizationContext.Current;
            UnityThreadId = Thread.CurrentThread.ManagedThreadId;
        }
anticrisis commented 6 years ago

@StephenHodgson Thank you for this -- I was unable to find documentation of this after quite a bit of searching Unity's forums. Never occurred to me to just build my project and see that my async worked, and of course it did. The code you shared makes the editor work, too.

Can this technique also be used to use the thread pool to run non-UI async tasks that don't need to access the Unity API?

Does anyone know if there is official Unity documentation on this anywhere?

jokigenki commented 6 years ago

Hi,

I've been experimenting with this a bit and async works as expected. However, I found it was of limited use since you can't touch any part of the Unity API, and most of the stuff I wanted to do ended up needing to go through the API. Depending on what you want it for, I'd recommend looking at the Unity Job System instead.

Owen

On Sat, 22 Sep 2018 at 03:21, anticrisis notifications@github.com wrote:

@StephenHodgson https://github.com/StephenHodgson Thank you for this -- I was unable to find documentation of this after quite a bit of searching Unity's forums. Never occurred to me to just build my project and see that my async worked, and of course it did. The code you shared makes the editor work, too.

Can this technique also be used to use the thread pool to run non-UI async tasks that don't need to access the Unity API?

Does anyone know if there is official Unity documentation on this anywhere?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/svermeulen/Unity3dAsyncAwaitUtil/issues/9#issuecomment-423628689, or mute the thread https://github.com/notifications/unsubscribe-auth/AAao1NCG0BzPVpVzjNsck0ipWXtmiU75ks5udS4wgaJpZM4WcPzU .

svermeulen commented 6 years ago

@jokigenki You should be able to use the unity api with the async approach provided here. Assuming you don't use the multithreading awaiters then it should all remain on the same thread. It should be able to be used in a very similar way to coroutines except a much cleaner syntax and some more features