Unload Scene When Pressing Play button through Editor Script

Hi, I am trying to create an editor script to help with my project development. I have organized my game into 2 scenes, one scene has some critical assets that the player needs at the very beginning, but the other scene has content that is loaded through the Addressables system later on.

I want to be able to test the entire workflow while having both scenes in the editor. I need to unload the scene with addressable content when I press the play button (it will then get loaded in naturally when the game starts playing).

I have found 3 API’s for this online, but all of them seem to be broken. I wrote this test script that outlines the 3 methods I tried.

First: EditorSceneManager.CloseScene
This doesn’t seem to do anything, no matter what parameters I pass to it.

Second: EditorSceneManager.UnloadScene
This also doesn’t do anything, and it is also marked as deprecated.

Third: EditorSceneManager.UnloadSceneAsync
This will unload the scene, but it doesn’t do it until multiple objects from the Addressable scene have finished their Awake functions, which causes errors in my game.

I tried all 3 of these functions in a static constructor with the [InitializeOnLoad] attribute and I also tried all 3 when subscribing to the EditorApplication.playModeStateChanged event and only the UnloadSceneAsync call actually unloaded the scene, but not before Awake functions were triggered.

Anyone have any experience with this sort of thing? Thanks!

using UnityEngine;
using UnityEditor;
using UnityEditor.SceneManagement;

// ensure class initializer is called whenever scripts recompile
[InitializeOnLoadAttribute]
public static class PlayModeStateChangedExample
{

    // register an event handler when the class is initialized
    static PlayModeStateChangedExample()
    {
        // Without checking this bool value, this code will be executed when the project is recompiled, so we will unload the addressables scene a lot.
        if (!EditorApplication.isPlayingOrWillChangePlaymode)
        {
            return;
        }

        // Get the Addressable content scene by name
        var addressableScene = EditorSceneManager.GetSceneByName("Template_4kPortrait_Addressable_Content");

        // Will print "scene path: Assets/Template_4kPortrait_Addressable_Content.unity" in the console
        //Debug.Log("scene path: " + addressableScene.path);

        // This function call does not unload the addressable scene. Passing true or false has no effect.
        //bool result = EditorSceneManager.CloseScene(addressableScene, true);

        // This function is deprecated. It also doesn't seem to work when called here.
        //bool result = EditorSceneManager.UnloadScene(addressableScene);

        // This function throws an error. System.InvalidOperationException: This can only be used during play mode, please use EditorSceneManager.CloseScene() instead.
        //EditorSceneManager.UnloadSceneAsync(@"Assets/Template_4kPortrait_Addressable_Content.unity", UnloadSceneOptions.UnloadAllEmbeddedSceneObjects);

        // Log for sanity.
        Debug.Log("Close addressable scene");

        // This event is triggered AFTER the game starts playing, so several Awake functions have already been fired.
        //EditorApplication.playModeStateChanged += LogPlayModeState;

    }

    /// <summary>
    /// This code will not run in time because it is triggered after the initial Awake functions are called on objects in the Addressables Scene
    /// </summary>
    /// <param name="state"></param>
    private static void LogPlayModeState(PlayModeStateChange state)
    {
        Debug.Log(state);

        // Get the Addressable content scene by name
        var addressableScene = EditorSceneManager.GetSceneByName("Template_4kPortrait_Addressable_Content");

        // This function call does not unload the addressable scene. Passing true or false has no effect.
        //bool result = EditorSceneManager.CloseScene(addressableScene, false);

        // This function is deprecated. It also doesn't work.
        //bool result = EditorSceneManager.UnloadScene(addressableScene);

        // This call works, but by the time it is finished, we will already have errors from multiple objects Awake calls being triggered and initializing things with the wrong object
        //EditorSceneManager.UnloadSceneAsync(@"Assets/Template_4kPortrait_Addressable_Content.unity");
    }


}

So what’s the actual use case here? Why do you need to unload a scene?

When you enter playmode, everything happens as it would in a build. The only difference being that you may have another scene besides the one indexed #0 in the build list open. If you need to launch that, you can make that happen by just loading that scene when enter playmode event tells you it’s about to “exit” edit mode. I’ve done that in the past to always enter playmode from a specific scene. This ensured that I had the “critical assets” scene always loaded first.

You do not need to do any editor side scene closing or unloading, you simply load a specific scene.

If you’re wishing to unload a scene, is there a scene left?

You’re likely too late when the editor is switching play mode. Unity might already be processing the scenes and prevent you from closing them.

EditorSceneManager.playModeStartScene could work for you. Set this to your main scene and only that scene should be loaded when entering play mode, regardless of what you have open in the editor, then you can load the rest through Addressables.

I try to structure my code so that I can play from any scene. Having to go through a specific process to load the game and get to a specific scene slows you down considerably while testing. Quickly editing something in a scene and being able to play it without saving the changes can also be really useful sometimes. So I’d generally advise to make your setup work with Unity’s regular workflow instead of forcing Unity into your own.

This is perfect, thanks so much!