Search Unity

list of open scenes

Discussion in 'Scripting' started by peterbrinson, Jun 20, 2019.

  1. peterbrinson

    peterbrinson

    Joined:
    Jul 1, 2013
    Posts:
    63
    Is there a way to find out if a particular scenes is already open and running? Before I asynchronously open a scene, I want to check to see if it's already open.
     
  2. Zalosath

    Zalosath

    Joined:
    Sep 13, 2014
    Posts:
    688
    SceneManager has an "isLoaded" Boolean.

    You call SceneManager.Scene.isLoaded to check for this.
     
  3. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,537
    Per documentation:
    https://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager.html

    SceneManager.sceneCount is the number of currently loaded scenes.
    SceneManager.GetSceneAt returns a Scene at that index in its list of loaded scenes (the list that sceneCount is the length of)

    So if you wanted to get an enumerable of all of them... something like:
    Code (csharp):
    1.  
    2. public static IEnumerable<Scene> GetAllLoadedScenes()
    3. {
    4.     for(int i = 0; i < SceneManager.sceneCount; i++)
    5.     {
    6.         yield return SceneManager.GetSceneAt(i);
    7.     }
    8. }
    9.  
    Or you could put them in an array, or a list, if you preferred.

    [edit]
    Sorry I interpretted your OP to want to know the names of all scenes loaded since the title was "list of open scenes".

    But you actually want to know if a particular scene is loaded.

    From this you can check if that scene's name is in that list.

    Or you could use SceneManager.GetSceneByName and check the 'isLoaded' property like previously mentioned.

    Or SceneManager.GetSceneByBuildIndex if you know its index rather than name.
     
    Alverik likes this.
  4. peterbrinson

    peterbrinson

    Joined:
    Jul 1, 2013
    Posts:
    63
    lorofduct,
    You're right that my subject is bit off.

    Yes, GetSceneByBuildIndex combined with .isLoaded, is the best because it'll go through every scene in my project, telling me what is currently loaded.
    The icing on the cake would be a var that tells me how many scenes GetSceneByBuildIndex can loop through, like "GetNumberOfScenesInBuild". Otherwise I just have to hardcode how many times I loop through....?
     
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    At Editor time you can tell from the EditorBuildSettings class, if that helps.

    I'm guessing at runtime you can also hit SceneUtility classes starting at zero and going up and maybe see if it returns a null when you go off the end? Or just catch the exception yourself and stop counting?

    Edit: here, check this, it's pretty straighforward: https://davikingcode.com/blog/retrieving-the-names-of-your-scenes-at-runtime-with-unity/
     
  6. peterbrinson

    peterbrinson

    Joined:
    Jul 1, 2013
    Posts:
    63
    This means I only need to store the int "EditorBuildSettings.scenes.Length" in the .asset file in my resources....when it runs in the editor. The stand-alone will only read that file.

    Now, I'm having a silly problem reading the scriptableobject that gets created when running in editor. It reads fine in editor, but is null in stand-alone. The "ScenesStore sStore =......" line returns null in stand-alone:

    Code (CSharp):
    1.   public class ScenesStore : ScriptableObject
    2.     {
    3.         public int scenesInBuildLength;
    4.     }
    5. void Start(){
    6.   ScenesStore sStore = Resources.Load<ScenesStore>("ScenesInBuildLength");
    7.         Debug.Log("--asset? " + sStore.name);
    8.         totalScenesInBuild = sStore.scenesInBuildLength;
    9.         Debug.Log("--here? " + totalScenesInBuild);
    }
     
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    The obvious first check is the usual suspect: is your ScenesStore object in folder called "Resources" ?
     
  8. peterbrinson

    peterbrinson

    Joined:
    Jul 1, 2013
    Posts:
    63
    Yes, it's "/Assets/Resources/ScenesInBuildLength.asset"

    ...and works like a charm in editor.
     
  9. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    Squints suspiciously at Unity... this is about the point when I reimport all... :)
     
  10. peterbrinson

    peterbrinson

    Joined:
    Jul 1, 2013
    Posts:
    63
    I appreciate your help. I've attached the asset file in case that can be read as text.

    Reimport didn't help and I'm certain this is my fault.

    Here is the bit that saves the int. You'll notice the #if UNITY_EDITOR because a couple of these classes are editor-only:

    Code (CSharp):
    1. #if UNITY_EDITOR
    2.     void SaveScenesNames()
    3.     {
    4.         // First, try to load the list if already exists
    5.         ScenesStore sceneStore = (ScenesStore)AssetDatabase.LoadAssetAtPath("Assets/Resources/ScenesInBuildLength.asset", typeof(ScenesStore));
    6.  
    7.         // If doesn't exist, create it !
    8.         if (sceneStore == null)
    9.         {
    10.             sceneStore = ScriptableObject.CreateInstance<ScenesStore>();
    11.             AssetDatabase.CreateAsset(sceneStore, "Assets/Resources/ScenesInBuildLength.asset");
    12.         }
    13.  
    14.         // Fill the int
    15.         sceneStore.scenesInBuildLength = EditorBuildSettings.scenes.Length;
    16.  
    17.         // Writes all unsaved asset changes to disk
    18.         AssetDatabase.SaveAssets();
    19.     }
    20. #endif
    ...and again how I read the asset in editor and stand-alone. It gives a null exception in stand-alone only

    Code (CSharp):
    1.         ScenesStore sStore = Resources.Load<ScenesStore>("ScenesInBuildLength");
    2.         Debug.Log("--asset? " + sStore.name);
     

    Attached Files:

    Last edited: Jun 21, 2019
  11. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    Looked at the asset and I suspect there's a problem with your ScriptableObject: your m_Script file ID is zero. It should be the GUID of the ScriptableObject class file's meta file. That's how Unity links stuff.

    Did you try putting your SO class definiition into its own file if it isn't already? And make that file named the same as the SO derivative, obviously, just like a Monobehaviour.

    Yours SceneStore instance:

    Code (csharp):
    1.  
    2. %YAML 1.1
    3. %TAG !u! tag:unity3d.com,2011:
    4. --- !u!114 &11400000
    5. MonoBehaviour:
    6.   m_ObjectHideFlags: 0
    7.   m_CorrespondingSourceObject: {fileID: 0}
    8.   m_PrefabInstance: {fileID: 0}
    9.   m_PrefabAsset: {fileID: 0}
    10.   m_GameObject: {fileID: 0}
    11.   m_Enabled: 1
    12.   m_EditorHideFlags: 0
    13.   m_Script: {fileID: 0}    <---- this can't be good!
    14.  m_Name: ScenesInBuildLength
    15.  m_EditorClassIdentifier: Assembly-CSharp::ManagerLevels/ScenesStore
    16.  scenesInBuildLength: 0
    An unrelated healthy-and-functional example SO-derived object from one of my random projects:

    Code (csharp):
    1.  
    2. %YAML 1.1
    3. %TAG !u! tag:unity3d.com,2011:
    4. --- !u!114 &11400000
    5. MonoBehaviour:
    6.   m_ObjectHideFlags: 0
    7.   m_CorrespondingSourceObject: {fileID: 0}
    8.   m_PrefabInstance: {fileID: 0}
    9.   m_PrefabAsset: {fileID: 0}
    10.   m_GameObject: {fileID: 0}
    11.   m_Enabled: 1
    12.   m_EditorHideFlags: 0
    13.   m_Script: {fileID: 11500000, guid: 0dd80a3df493a44e488bb676b9005058, type: 3}
    14.   m_Name: Rat1
    15.   m_EditorClassIdentifier:
    16.   Description: Small rat
    17.   Count: 1
    18.   Level: 1
    19.  
    Note how my m_Script field is nonzero. That guid is the GUID for the SO-derived class file in my case.
     
  12. peterbrinson

    peterbrinson

    Joined:
    Jul 1, 2013
    Posts:
    63
    I made a new C# file named, ScenesStore.cs with this content

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class ScenesStore : ScriptableObject
    6. {
    7.     public int scenesInBuildLength;
    8. }
    ...I deleted the old asset and rand the project again to make a new asset. But the m_Script is still 0. Somehow, I'm not creating this asset correctly....?
     
  13. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    Whacky. I copy-pasted your code and it works fine for me, using Unity 2018.4.2 (latest I had on hand).

    I did add the create decorator though: (ScenesStore.cs) I added the CreateAssetMenu decorator because I forgot the old way of making ScriptableObject instances and I never want to remember it again. :)

    Code (csharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. [CreateAssetMenu]
    6. public class ScenesStore : ScriptableObject
    7. {
    8.     public int scenesInBuildLength;
    9. }
    And here's the asset that it generated:

    Code (csharp):
    1. %YAML 1.1
    2. %TAG !u! tag:unity3d.com,2011:
    3. --- !u!114 &11400000
    4. MonoBehaviour:
    5.   m_ObjectHideFlags: 0
    6.   m_CorrespondingSourceObject: {fileID: 0}
    7.   m_PrefabInstance: {fileID: 0}
    8.   m_PrefabAsset: {fileID: 0}
    9.   m_GameObject: {fileID: 0}
    10.   m_Enabled: 1
    11.   m_EditorHideFlags: 0
    12.   m_Script: {fileID: 11500000, guid: d376730f030644e36a26a7554baadfbe, type: 3}
    13.   m_Name: SceneStoreAsset
    14.   m_EditorClassIdentifier:
    15.   scenesInBuildLength: 0
    And then as far as the script goes, this is the metafile: (ScenesStore.cs.meta)

    Code (csharp):
    1. fileFormatVersion: 2
    2. guid: d376730f030644e36a26a7554baadfbe
    3. MonoImporter:
    4.   externalObjects: {}
    5.   serializedVersion: 2
    6.   defaultReferences: []
    7.   executionOrder: 0
    8.   icon: {instanceID: 0}
    9.   userData:
    10.   assetBundleName:
    11.   assetBundleVariant:
     
  14. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    Oh yeah, how DID your editor script create it?

    I take it you used ScriptableObject.CreateInstance<ScenesStore>(); to generate it, right??

    Pretty sure if you try to just new() one up it won't work.
     
  15. peterbrinson

    peterbrinson

    Joined:
    Jul 1, 2013
    Posts:
    63
    You did it.
    My last post was wrong, sorry. I didn't integrate the scriptableObject class file correctly, but my journey was otherwise instructive.

    To summarize, the solution was to put
    Code (CSharp):
    1. public class ScenesStore : ScriptableObject
    in a separate .cs file.

    Thank you Kurt.
     
    Kurt-Dekker likes this.
  16. giantkilleroverunity3d

    giantkilleroverunity3d

    Joined:
    Feb 28, 2014
    Posts:
    383
    It would be nice to read the project panel data directly. Unity does it so how come that process is not documented?
     
  17. giantkilleroverunity3d

    giantkilleroverunity3d

    Joined:
    Feb 28, 2014
    Posts:
    383