Search Unity

Freeze on await for InstantiateAsync or LoadAssetAsync in Build (Windows)

Discussion in 'Addressables' started by Chrueschsch1e, Feb 20, 2020.

  1. Chrueschsch1e

    Chrueschsch1e

    Joined:
    Jan 28, 2020
    Posts:
    16
    Hello hello!

    My problem:
    I want/need to load prefabs with Addressables and use them immediately.
    I have the following code:
    Code (CSharp):
    1. private async Task LoadCube()
    2. {
    3.     AsyncOperationHandle<GameObject> handle =
    4.         Addressables.InstantiateAsync("Cube");
    5.     Log("before waiting");
    6.     await handle.Task;
    7.     Log("after waiting");
    8. }
    or
    Code (CSharp):
    1. private async Task LoadCube()
    2. {
    3.     AsyncOperationHandle<GameObject> handle =
    4.         Addressables.LoadAssetAsync<GameObject>("Cube");
    5.     Log("before waiting");
    6.     await handle.Task;
    7.     Log("after waiting");
    8. }
    In the Unity Editor everything works as expected: I see both messages in my log file.
    But later in the build (built for Windows) it always freezes on the
    await handle.Task;

    I do not see the 'after waiting' line. As if there is some problem with instantiating/loading the prefab.
    But there should be no problem: I can instantiate/load the prefab just fine, when I am not awaiting the handle...

    What I tried:
    I tested with different prefabs, different Unity versions (2019.3.1 and now 2019.3.2), and different versions of the Addressables package (first the most recent 1.6.2 and now the 2019.3-verified 1.1.10).

    I read on the interwebs about deadlocking the GUI thread with async+await, and fixing it with
    await handle.Task.ConfigureAwait(false);
    , but it did not help (which would have surprised me, since I did not see it in any of the Addressables examples...).

    Am I missing something here? I am out of ideas. Any help would be much appreciated!
    Thank you and greetings,
    Christian
     
    Threeyes and SudoCat like this.
  2. TreyK-47

    TreyK-47

    Unity Technologies

    Joined:
    Oct 22, 2019
    Posts:
    1,820
    Sorry to hear you're having trouble! We'll circulate this with the team for you.
     
    Chrueschsch1e likes this.
  3. davidla_unity

    davidla_unity

    Unity Technologies

    Joined:
    Nov 17, 2016
    Posts:
    763
    @Chrueschsch1e That is quite odd. We'll have to look into that. Can you submit a bug with Unity and post the case number here? If at all possible please attach your project. In the event we can't reproduce it on a fresh project we can use your project to reproduce the issue.
     
    dan_soqqle and Chrueschsch1e like this.
  4. SudoCat

    SudoCat

    Joined:
    Feb 19, 2013
    Posts:
    64
    I have been encountering the same issue. I have raised a bug report with a simplified test case showcasing the various permutations of this issues.

    http://fogbugz.unity3d.com/default.asp?1222698_cs7v717m16hvq3cs
     
    davidla_unity and Chrueschsch1e like this.
  5. Chrueschsch1e

    Chrueschsch1e

    Joined:
    Jan 28, 2020
    Posts:
    16
    @SudoCat Thank you for your input. I am glad I am not the only one with this problem.
    @TreyK-47 and @DavidUnity3d Thank you too for your replies. Sadly I am not able to provide our project in a bug report.


    At least I managed to narrow down my problem a bit:
    The class that is loading my prefabs is not a MonoBehaviour class. Here the await-problem occurs.

    However, if I instantiate any prefab in any MonoBehaviour's Start() method (with
    Addressables.InstantiateAsync()
    ), everything else later works fine. I can then await load any prefab in my Non-MonoBehaviour as expected.

    I can even
    GameObject.Destroy()
    the instance from the beginning (not with
    Addressables.ReleaseInstance()
    ), and it still works.

    If I call
    Addressables.ReleaseInstance()
    on the instance from the beginning, I can again not await load anything in my Non-MonoBehaviour later.

    I hope I was able to express myself without causing confusion.
    My guess is that only as long as I have a reference to a loaded Addressable lying around somewhere, Unity is able to await load via Addressables in Non-Monobehaviours too?
     
  6. Chrueschsch1e

    Chrueschsch1e

    Joined:
    Jan 28, 2020
    Posts:
    16
    I have to go back on my words from my previous post a little.
    It's not enough to load a single prefab in the beginning from a MonoBehaviour's Start() method.

    It seems I have to load every prefab in the Start() method once, if I want to await load it later from a Non-MonoBehaviour class.
    It's also enough to call
    Addressables.LoadAssetAsync<GameObject>()
    in a Start() method and never release it. Then I can use
    Addressables.InstantiateAsync()
    with await in from Non-MonoBehaviour class later.
     
  7. Efril

    Efril

    Joined:
    Aug 31, 2013
    Posts:
    82
    It seems that the issue still exist. I'm trying to switch from one scene to another and show the third scene with loading screen and progress bar between them. AssetReferences should be loaded in the loading screen scene and passed to the final scene (so assets should be ready to use before Awake() of the final scene scripts are called). All working as expected in Unity editor but in the standalone build AssetReferences are never loaded.
    I'm able to reproduce the issue in a very simple project.
    1. The script below is attached to a button in the initial scene and clicking this button initiates loading process.
    Code (CSharp):
    1. internal class SceneLoadingButton : MonoBehaviour
    2. {
    3.     /// <summary>
    4.     /// Reference to the asset that should be loaded for usage in the final scene
    5.     /// </summary>
    6.     [SerializeField]
    7.     private AssetReference _assetToLoad;
    8.  
    9.     private void Start()
    10.     {
    11.         this.GetComponent<Button>().onClick.AddListener(LoadScene);
    12.     }
    13.  
    14.     /// <summary>
    15.     /// Handler of the button which initiates switching scenes.
    16.     /// </summary>
    17.     private void LoadScene()
    18.     {
    19.         //Create new game object that will leave between the scenes and performs loading scenes and an asset
    20.         new GameObject().AddComponent<SceneLoader>().Load(_assetToLoad);
    21.     }
    22. }
    2. Scene loader that persists between the scenes and loads scenes and an asset.
    Code (CSharp):
    1. internal class SceneLoader : MonoBehaviour
    2. {
    3.     private static readonly WaitForSeconds _waitForSeconds01Yield = new WaitForSeconds(0.1f);
    4.     /// <summary>
    5.     /// Reference to the asset that should be loaded for usage in the final scene
    6.     /// </summary>
    7.     private AssetReference _assetToLoad;
    8.     private GameObject _loadedAsset;
    9.     /// <summary>
    10.     /// Asset is loaded flag
    11.     /// </summary>
    12.     private bool _assetIsLoaded = false;
    13.  
    14.     public void Load(AssetReference AssetToLoad)
    15.     {
    16.         _assetToLoad = AssetToLoad;
    17.         //Load the loading screen scene asynchroniously
    18.         AsyncOperation loadingScreenSceneAsyncOperation = SceneManager.LoadSceneAsync("LoadingScreenScene");
    19.         loadingScreenSceneAsyncOperation.completed += LoadingScreenScene_completed;
    20.     }
    21.  
    22.     private void LoadingScreenScene_completed(AsyncOperation obj)
    23.     {
    24.         //Loading screen scene is loaded. Start to load the final scene and the asset
    25.         StartCoroutine(LoadingFinalSceneCoroutine());
    26.     }
    27.  
    28.     private IEnumerator LoadingFinalSceneCoroutine()
    29.     {
    30.         AsyncOperation sceneLoadingAsyncOperation = SceneManager.LoadSceneAsync("FinalScene");
    31.         sceneLoadingAsyncOperation.allowSceneActivation = false;
    32.  
    33.         //Star loading the asset asynchroniously
    34.         StartLoadingAsset();
    35.  
    36.         //Waiting for the asset to load
    37.         while (!_assetIsLoaded)
    38.         {
    39.             yield return _waitForSeconds01Yield;
    40.         }
    41.  
    42.         //Never gonna get here in the standalone build but everything works fine in the editor
    43.         while (sceneLoadingAsyncOperation.progress < 0.9f)
    44.         {
    45.             yield return _waitForSeconds01Yield;
    46.         }
    47.  
    48.         sceneLoadingAsyncOperation.allowSceneActivation = true;
    49.     }
    50.  
    51.     private async void StartLoadingAsset()
    52.     {
    53.         _loadedAsset = await _assetToLoad.LoadAssetAsync<GameObject>().Task;
    54.         //Never gonna get here in the standalone build but everything works fine in the editor
    55.         _assetIsLoaded = true;
    56.     }
    57.  
    58.     private void Awake()
    59.     {
    60.         //Keep scene loader game object between the scenes
    61.         DontDestroyOnLoad(this.gameObject);
    62.     }
    63. }
    I tried many variants of this code but none of them is working. The only way to make it work seems to load the final scene synchroniously but it is slower and does not allow to show correct loading progress to a player.
    Code (CSharp):
    1.  
    2.     private IEnumerator LoadingFinalSceneCoroutine()
    3.     {
    4.         StartLoadingAsset();
    5.         while(!_assetIsLoaded)
    6.         {
    7.             yield return _waitForSeconds01Yield;
    8.         }
    9.         SceneManager.LoadScene("FinalScene");
    10.     }
    The described scenario with a loading screen and a progress bar seems to be very common and it is very sad that Addressables does not work with it.
     
    Last edited: Dec 4, 2020
  8. TreyK-47

    TreyK-47

    Unity Technologies

    Joined:
    Oct 22, 2019
    Posts:
    1,820
  9. Efril

    Efril

    Joined:
    Aug 31, 2013
    Posts:
    82
    TreyK-47 likes this.
  10. won-gyu

    won-gyu

    Joined:
    Mar 23, 2018
    Posts:
    35
    I had the same issue.
    I'm not sure what I did was a fundamental solution, but I happened to fix it.
    In my case, loading addressable assets right after an async scene loading causes this issue.

    BEFORE I fixed:
    1. loading scene async (escape my loading coroutine function when progress is over 0.9)
    2. loading addressable assets async (freeze here)
    3. activate scene

    AFTER:
    1. loading addressable assets async
    2. loading scene async (escape my loading coroutine function when progress is over 0.9)
    3. activate scene

    I hope it helps.
     
    meszolymilan008 and NguyenKyAnh like this.
  11. ANTONBORODA

    ANTONBORODA

    Joined:
    Nov 16, 2017
    Posts:
    52
    It's kind of amazing how bugs like this are just ignored. I just wasted 4 hours of my time trying to understand what is wrong with my code and why the scene is not loading, only coming to this thread and finding out this is actually a bug. Good lord...
     
    Chrueschsch1e likes this.
  12. unity_62SfK2Y5Ec2uhQ

    unity_62SfK2Y5Ec2uhQ

    Joined:
    May 5, 2021
    Posts:
    1
    Same issue happens also in our project.

    Repro steps are (Unity 2022.3.21f1):
    1. We start a INTRO scene.
    2. After user dialog the same INTRO scene is loaded again (sync).
    3. Then after some action scene MAIN_MENU is loaded.
    4. In the Awake method in the MAIN_MENU scene we InstantiateAsync which fails.

    When we load the MAIN_MENU skipping step 2, then the loading works correctly and the assets are instantiated without problem.

    I have fixed it by manually calling await UnityServices.InitializeAsync(); on the start of INTRO scene. For some reason it started working. However I have spend roughly 4 hours (just shier luck I found this workaround) just trying to work around this and its really awful from Unity to leave bugs like this lying around. Well, let's see what other things this breaks...