Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Detect if SceneView is currently Prefab Isolation Mode

Discussion in 'Prefabs' started by equalsequals, Jan 29, 2019.

  1. equalsequals

    equalsequals

    Joined:
    Sep 27, 2010
    Posts:
    154
    As the title says, is there an API that can help detect if the active SceneView is currently displaying Prefab Isolation Mode?

    We are experiencing some visual issues from our SRP when editing a Prefab, which could be resolved simply by bypassing the special Pass when the SceneView is in this state.

    Thanks in advance.
     
    SamFernGamer4k and mdrunk like this.
  2. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,294
  3. equalsequals

    equalsequals

    Joined:
    Sep 27, 2010
    Posts:
    154
    Many thanks. I tried searching the docs for so many string combinations and I wasn't quite sure what I was looking for.
     
  4. MatthieuPr

    MatthieuPr

    Joined:
    May 4, 2017
    Posts:
    56
    you can also use
    bool isPrefabInstance = PrefabUtility.IsPartOfPrefabInstance(target);

    if it is true it means you are not in prefab isolation for that specific prefab, after that in editor scripting you can use

    using (new EditorGUI.DisabledScope(isPrefabInstance))
    {}
    the will grab out everything inside the using in the inspector and not allow to interact with it :)
     
  5. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    That is not always true and thus not reliable. If you have a Prefab Variant open in Prefab Mode, then the content is itself a Prefab instance, and thus IsPartOfPrefabInstance will return true.

    Use the method posted by Baste.
     
  6. MatthieuPr

    MatthieuPr

    Joined:
    May 4, 2017
    Posts:
    56
    PrefabStageUtility.GetCurrentPrefabStage tells you when you are in prefab stage, but doesn't inform you that current prefab script is attached on is the one that is opened in the prefab stage. That requires to also check the IsPartOfPrefabInstance(target).
     
  7. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    phobos2077 and CianNoonan like this.
  8. guneyozsan

    guneyozsan

    Joined:
    Feb 1, 2012
    Posts:
    99
  9. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,294
    That's not how defines work. They're either active or not active for the entire code base. You'd have to recompile the entire project every time you entered or exited play mode.
     
    guneyozsan likes this.
  10. ATLGAN

    ATLGAN

    Joined:
    Oct 15, 2017
    Posts:
    10
  11. Stevens-R-Miller

    Stevens-R-Miller

    Joined:
    Oct 20, 2017
    Posts:
    676
    This works, but it relies on the UnityEditor.Experimental.SceneManagement namespace, which I can't use when building a player. How can we create a prefab that executes its Start method when added to a scene, but not when opened for editing the prefab, and still include that prefab in a build?
     
  12. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,294
    You can wrap the use of UnityEditor.Experimental.SceneManagement in #if UNITY_EDITOR
     
    CladCobra likes this.
  13. Stevens-R-Miller

    Stevens-R-Miller

    Joined:
    Oct 20, 2017
    Posts:
    676
    Yeah, that works. I note that the UnityEditor.Experimental.SceneManagement namespace is still in Unity 2020.1. I'm using 2018.4 (the latest LTS version), and there is a slight difference to the contents. Wish there were some way to do this that relied on something not labeled "experimental." But your method does work, so thanks!
     
  14. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    In 2020.1+ there is a way that's not experimental:
    https://docs.unity3d.com/2020.1/Doc...ce/SceneManagement.StageUtility.GetStage.html
    But of course that doesn't help when using an earlier version than that, unfortunately.
     
    iSinner likes this.
  15. paintpaul

    paintpaul

    Joined:
    Mar 8, 2017
    Posts:
    21
  16. KSzczech

    KSzczech

    Joined:
    Sep 24, 2020
    Posts:
    30
    Old thread, but I've been working on something similar, stumbled here, so I'm leaving a solution for people who will stumple here in future :)

    in C++ it would be possible to have a dynamic call behind a #define, butt in c# these are just static tags at compile time.

    But there's a better way in c# - using extension functions you can add new methods to existing classes. So you can extend, for example, GameObject, by defining such extension class somewhere:
    Code (CSharp):
    1. public static class GameObjectExtension
    2. {
    3.     public static bool IsBeingEditedInIsolatedPrefabMode( this GameObject obj )
    4.     {
    5.         return PrefabStageUtility.GetPrefabStage( obj ) != null;
    6.     }
    7. }
    And now you can call it directly on your game objects like this:
    Code (CSharp):
    1. if ( myGameObject.IsBeingEditedInIsolatedPrefabMode() )
    2. {
    3.     Debug.Log("Hey dude!");
    4. }
     
  17. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    2,364
    I agree the documentation is ridiculously under-helpful.

    The first part of this code snippet is how I am using it. The whole snippet is for an editor-only button I use to unpack and prepare a special prefab instance before injecting its dependencies.

    Code (CSharp):
    1. #if UNITY_EDITOR
    2. using UnityEditor;
    3. using UnityEditor.SceneManagement;
    4. #endif
    5.  
    6. //...
    7.  
    8. #if UNITY_EDITOR
    9.             if (StageUtility.GetStage(gameObject) != StageUtility.GetMainStage())
    10.             {
    11.                 Debug.LogWarning($"We're in a special Editing Stage");
    12.                 return false;
    13.             }
    14.             if (gameObject.scene.rootCount == 0)
    15.             {
    16.                 Debug.LogWarning($"This is an original Prefab Asset");
    17.                 return false;
    18.             }
    19.             GameObject root =
    20.                 PrefabUtility.GetOutermostPrefabInstanceRoot(gameObject);
    21.             if (root == null)
    22.             {
    23.                 Debug.LogWarning($"This is not part of a prefab instance");
    24.                 return false;
    25.             }
    26.             Debug.LogWarning($"We're in the Main Editing Stage, unpacking");
    27.             Selection.activeGameObject = root;
    28.             PrefabUtility.UnpackPrefabInstance(root,
    29.                 PrefabUnpackMode.Completely,
    30.                 InteractionMode.AutomatedAction);
    31. #endif
     
    Last edited: Mar 7, 2023
    AnomalusUndrdog and paintpaul like this.
  18. sfider

    sfider

    Joined:
    Jan 10, 2019
    Posts:
    12
    Again, old thread, but I've been working on something similar XD

    The proposed method can give unexpected results when your prefab is nested inside another prefab. If you're editing the outer prefab, this code will return true for the nested prefab. It could be what you're looking for, but if you're interested in testing if the prefab asset being edited is the most basic prefab asset containing your script, you need an additional check.

    My idea was to check assetPath property of the PrefabStage against the assetPath on the nearest instance root. The problem is method for that returns empty string for currently edited prefab, but a proper assetPath for nested prefabs, so I ended with something like this:
    Code (CSharp):
    1. public static class GameObjectExtension
    2. {
    3.     public static bool IsBeingEditedInIsolatedPrefabMode(this GameObject gameObject)
    4.     {
    5.         PrefabStage stage = PrefabStageUtility.GetPrefabStage(gameObject);
    6.         string prefabPath = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(gameObject);
    7.         return stage != null && (stage.assetPath == prefabPath || string.IsNullOrEmpty(prefabPath));
    8.     }
    9. }
    In the end I resolved my problem with other, not prefab related, check. So I'm not sure how robust is this solution ;)