Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
jokigenki opened this issue Sep 6, 2018 · 7 comments

Comments

@jokigenki
Copy link

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
Copy link
Contributor

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
Copy link
Contributor

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

@StephenHodgson
Copy link

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
Copy link

StephenHodgson commented Sep 7, 2018

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
Copy link

@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
Copy link
Author

jokigenki commented Sep 22, 2018 via email

@svermeulen
Copy link
Contributor

svermeulen commented Sep 22, 2018

@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

AwesomesauceLabs pushed a commit to AwesomesauceLabs/Unity3dAsyncAwaitUtil that referenced this issue Nov 3, 2019
As per modesttree/Unity3dAsyncAwaitUtil/modesttree#9, using Unity3dAsyncAwaitUtil in
Editor scripts causes an NPE, because `SyncContextUtil.Install` is never called
to initialize global variables `SyncContextUtil.UnitySynchronizationContext` and
`SyncContextUtil.UnityThreadId`.

Fix this by adding the `[InitializeOnLoadMethod()]` attribute to the
`SyncContextUtil.Install` method. Note that the existing
`[RuntimeInitializeOnLoadMethod]` attribute is still needed in order for
`SyncContextUtil.Install` to be invoked when entering Play Mode.

Fixes modesttree/Unity3dAsyncAwaitUtil/modesttree#9
AwesomesauceLabs added a commit to AwesomesauceLabs/Unity3dAsyncAwaitUtil that referenced this issue Nov 3, 2019
As per modesttree/Unity3dAsyncAwaitUtil/modesttree#9, using Unity3dAsyncAwaitUtil in
Editor scripts causes an NPE, because `SyncContextUtil.Install` is never called
to initialize global variables `SyncContextUtil.UnitySynchronizationContext` and
`SyncContextUtil.UnityThreadId`.

Fix this by adding the `[InitializeOnLoadMethod()]` attribute to the
`SyncContextUtil.Install` method. Note that the existing
`[RuntimeInitializeOnLoadMethod]` attribute is still needed in order for
`SyncContextUtil.Install` to be invoked when entering Play Mode.

Fixes modesttree/Unity3dAsyncAwaitUtil/modesttree#9
AwesomesauceLabs added a commit to AwesomesauceLabs/Unity3dAsyncAwaitUtil that referenced this issue Nov 4, 2019
As per modesttree/Unity3dAsyncAwaitUtil/modesttree#9, using Unity3dAsyncAwaitUtil in
Editor scripts causes an NPE, because `SyncContextUtil.Install` is never called
to initialize global variables `SyncContextUtil.UnitySynchronizationContext` and
`SyncContextUtil.UnityThreadId`.

Fix this by adding the `[InitializeOnLoadMethod()]` attribute to the
`SyncContextUtil.Install` method. Note that the existing
`[RuntimeInitializeOnLoadMethod]` attribute is still needed in order for
`SyncContextUtil.Install` to be invoked when entering Play Mode.

Fixes modesttree/Unity3dAsyncAwaitUtil/modesttree#9
AwesomesauceLabs pushed a commit to AwesomesauceLabs/Unity3dAsyncAwaitUtil that referenced this issue Nov 6, 2019
As described modesttree#9, using Unity3dAsyncAwaitUtil in
Editor scripts causes an NPE, because `SyncContextUtil.Install` is never called
to initialize global variables `SyncContextUtil.UnitySynchronizationContext` and
`SyncContextUtil.UnityThreadId`.

Fix this by adding the `[InitializeOnLoadMethod()]` attribute to the
`SyncContextUtil.Install` method. Note that the existing
`[RuntimeInitializeOnLoadMethod]` attribute is still needed in order for
`SyncContextUtil.Install` to be correctly invoked in Play Mode.

Fixes modesttree#9
AwesomesauceLabs pushed a commit to AwesomesauceLabs/Unity3dAsyncAwaitUtil that referenced this issue Nov 8, 2019
dubois added a commit to dubois/Unity3dAsyncAwaitUtil that referenced this issue Dec 4, 2019
If the package com.unity.editorcoroutine is installed,
AsyncCoroutineRunner gains the ability to work at edit time.

In Unity 2019.1 and above, no additional setup is needed.
Otherwise, the symbol HAVE_EDITOR_COROUTINES must also be
manually defined.

Includes unit test.
Addresses part of modesttree#9
dubois added a commit to dubois/Unity3dAsyncAwaitUtil that referenced this issue Dec 4, 2019
Includes sample unit test showing that "await" works at edit time.

Fixes modesttree#9
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants