(Case 931488) PostProcessSceneAttribute not called after loading scene

The PostProcessSceneAttribute documentation says:

In 2017.2.0b3, the method is only called when entering Playmode, the method is not called when additively loading a scene.

My test case loads 4 additive scenes, printing what scene is about to be loaded to the Console window. Then I have a PostProcessScene callback that prints the current sceneCount to the Console window. This allows me to see at what point and how often the PostProcessScene callback is fired.

Code

public class Loader : MonoBehaviour
{
    System.Collections.IEnumerator Start()
    {
        yield return null;

        Debug.Log("Loading Scene_2");
        UnityEngine.SceneManagement.SceneManager.LoadScene("Scene_2", UnityEngine.SceneManagement.LoadSceneMode.Additive);

        Debug.Log("Loading Scene_3");
        UnityEngine.SceneManagement.SceneManager.LoadScene("Scene_3", UnityEngine.SceneManagement.LoadSceneMode.Additive);

        AsyncOperation asyncOp = null;
        Debug.Log("Loading Scene_4");
        asyncOp = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync("Scene_4", UnityEngine.SceneManagement.LoadSceneMode.Additive);
        while(!asyncOp.isDone)
            yield return null;

        Debug.Log("Loading Scene_5");
        asyncOp = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync("Scene_5", UnityEngine.SceneManagement.LoadSceneMode.Additive);
        while(!asyncOp.isDone)
            yield return null;
    }
}


static class SceneProcessor
{
    [PostProcessScene]
    static void OnPostProcessScene()
    {
        var text = new System.Text.StringBuilder();
        text.AppendFormat("  OnPostProcessScene: sceneCount={0}\n", UnityEngine.SceneManagement.SceneManager.sceneCount);
        for(var n = 0; n < UnityEngine.SceneManagement.SceneManager.sceneCount; ++n)
            text.AppendFormat("{0}\n", UnityEngine.SceneManagement.SceneManager.GetSceneAt(n).name);

        Debug.Log(text.ToString());
    }
}

Reproduce

  • Open user project
  • Open Asset/Scenes/Scene_1
  • Press Play

Observe that it outputs:

OnPostProcessScene: sceneCount=1
Loading Scene_2
Loading Scene_3
Loading Scene_4
Loading Scene_5

It only called the PostProcessScene method when entering Playmode.

Expected
The test should output:

OnPostProcessScene: sceneCount=1
Loading Scene_2
OnPostProcessScene: sceneCount=2
Loading Scene_3
OnPostProcessScene: sceneCount=3
Loading Scene_4
OnPostProcessScene: sceneCount=4
Loading Scene_5
OnPostProcessScene: sceneCount=5

PostProcessScene method called when entering Playmode and after having loaded every single scene.

Please also take a look at the Feedback item I created regarding the PostProcessSceneAttribute, because I believe it lacks an important argument.
https://feedback.unity3d.com/suggestions/postprocesssceneattribute-provide-scene-argument-callback-method

1 Like

Yes, there isnā€™t any way to know which scene we are processing when a scene is loaded additive in 2017.1 either. In 2017.1 I can additively load 3 scenes at the same time. I get PostProcessScene called 3 times, but in all 3 calls the scene count is 4. (All scenes are present). Not sure which ā€˜sceneā€™ the call is ā€˜forā€™.

I was using SceneManager.GetSceneAt(SceneManager.sceneCount - 1) to figure out the current scene, but this doesnā€™t work when loading multiple scenes at the same time.

They introduced the IProcessScene API in 5.6 or 2017.1, which provides the Scene itā€™s processing on:
https://docs.unity3d.com/ScriptReference/Build.IProcessScene.OnProcessScene.html

I havenā€™t used it yet, but it looks like itā€™s a replacement for the PostProcessSceneAttribute.

Kind of unrelated, but I recommend to at least try/test if loading scenes sequentially improves loading times.

I loaded 5 scenes in parallel in my game too. I changed it to load scenes sequentially as an attempt to avoid the enormous cost of ā€œasset integration stepsā€. Luckily, it did improve loading times in the editor significantly and causes way less hiccups in the build.

Thanks Peter. Iā€™ll try the sequential load when I get into the office on Monday.

Iā€™ll also have to see if the IProcessScene will get invoked when playing in the editor too, since we rely on that functionality. (PostProcessScene runs just before we enter the scene so we can prepare the scene the same way we do for a build while we test in the editor.)

From the documentation description it sounds like it only runs during the build process. (Which would be a shame. I canā€™t think of many/any post processing operations I would only want to run when building*.)*

I apply scene post processing when doing a build only.

The reason behind this approach is to keep ā€œEnterPlayModeā€ time as fast as possible. I iterate a lot in the editor and every second I donā€™t have to stare at frozen Unity when pressing Play makes a difference for me. :slight_smile: However, I have several rather expensive processors, such as baking static meshes and the like.

I see. Havenā€™t thought about using it like that! We use PostProcessScene to generate UGUI elements based on data in our project. For example, we have a tech tree with nodes and connections between nodes defined in a scriptable asset. We have a Tech Tree Generator script that instantiates UGUI UI elements on PostProcessScene in our menu scene to build the tree by reading that data. So every time we build and every time we hit play in the editor, our UI is up to date with the most recent data! (We do more than just a tech tree :slight_smile: ). Hoping I can reproduce this with IProcessScene.

@Peter77 I just did a small test, the callback is called when changing scenes in the editor too. :slight_smile: Sweet!

I repeated your test, the output is:

  OnProcessScene: sceneCount=1
    Scene_1
Loading Scene_2
Loading Scene_3
Loading Scene_4
  OnProcessScene: sceneCount=4
    Scene_2
  OnProcessScene: sceneCount=4
    Scene_3
  OnProcessScene: sceneCount=4
    Scene_4
Loading Scene_5
  OnProcessScene: sceneCount=5
    Scene_5

Code:

using System.Text;
using UnityEditor.Build;
using UnityEngine;
using UnityEngine.SceneManagement;

public class Loader : MonoBehaviour
{
    public static StringBuilder result = new StringBuilder();
    System.Collections.IEnumerator Start()
    {
        yield return null;

        result.Append("Loading Scene_2\n");
        UnityEngine.SceneManagement.SceneManager.LoadScene("Scene_2", UnityEngine.SceneManagement.LoadSceneMode.Additive);

        result.Append("Loading Scene_3\n");
        UnityEngine.SceneManagement.SceneManager.LoadScene("Scene_3", UnityEngine.SceneManagement.LoadSceneMode.Additive);

        AsyncOperation asyncOp = null;
        result.Append("Loading Scene_4\n");
        asyncOp = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync("Scene_4", UnityEngine.SceneManagement.LoadSceneMode.Additive);
        while (!asyncOp.isDone)
            yield return null;

        result.Append("Loading Scene_5\n");
        asyncOp = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync("Scene_5", UnityEngine.SceneManagement.LoadSceneMode.Additive);
        while (!asyncOp.isDone)
            yield return null;

        Debug.Log(Loader.result.ToString());
    }
}


class SceneProcessor : IProcessScene
{
    public int callbackOrder { get; private set; }
    public void OnProcessScene(Scene scene)
    {
        Loader.result.AppendFormat("  OnProcessScene: sceneCount={0}\n", UnityEngine.SceneManagement.SceneManager.sceneCount);
        Loader.result.AppendFormat("    {0}\n", scene.name);
    }
}
1 Like

Thatā€™s great, so it seems to be fixed mostly! What Unity version did you use to run the test?

2017.2.0b8 (Little outdated on my home PC :wink: )

Just a note, in 2017.1 IProcessScene is broken :stuck_out_tongue: I was excited to use this instead of PostProcessScene but it doesnā€™t work. When you addtively load scenes, you get an IProcessScene callback for each scene youā€™ve loaded, but the scene object being passed in to your callback is the same as the active scene every time. ie Load Scene1 and additive load Scene2 + Scene3 means you get 3 IProcessCallbacks, but if you log out scene.name, it is Scene1 for all 3 calls. :stuck_out_tongue:

This seems to be fixed in 2017.2.0b8 and up (?) I donā€™t have 2017.2 in the office, we will wait for release candidate 3 before we download and then try it out again.

I ran into the same issue just a few hours ago! I was updating the code to use IProcessScene and then got the callback for the same scene always, just as you described.

Itā€™s always fascinating how something that seems so simple is just broken. Not only should it easy to test during development, it seems itā€™s also a good candidate for an automated test.

Iā€™m glad they didnā€™t remove the old API at the same time they introduced IProcessScene, because then weā€™d be screwed.

Agreed. Their internal QA seems like it could use a little bit of work. I have no doubt they have some QA, but still - too many little things fly under the radarā€¦

I remember a few betas back (Maybe for 5.6 beta? Earlier?)ā€¦ They introduced the ability to create an Editor Script instead of a regular script from the project window context menu. Turned out the developer had left in some test logsā€¦ Selecting ā€˜Editor Scriptā€™ from the context menu would create your script but then it would also log out ā€œTestā€ as an error in to the console. How did this get past QA? How did this make it to an actual release? Did the developer just push their changes to master and bam! It was in the release, no testing done what so ever?