Search Unity

Test if prefab is an instance

Discussion in 'Prefabs' started by xVergilx, Sep 30, 2018.

  1. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    There might be a simple answer to this, but I can't seems to find it.

    Previously, it was possible to check if the prefab is actually a prefab in the project, and not the instance in the scene. Now, I wonder, is there a new way to do so?

    PrefabUtility.GetPrefabAssetType() seems to be returning an enum, but none of it's values clearly state that prefab is an instance.

    Is there any?
     
    GoblinGameWorks likes this.
  2. SteenLund

    SteenLund

    Unity Technologies

    Joined:
    Jan 20, 2011
    Posts:
    639
    Hi,

    As of 2018.3 we split
    PrefabUtility.GetPrefabType
    into
    PrefabUtility.GetPrefabAssetType
    and
    PrefabUtility.GetPrefabInstanceStatus
    .

    https://docs.unity3d.com/2018.3/Documentation/ScriptReference/PrefabUtility.GetPrefabAssetType.html
    https://docs.unity3d.com/2018.3/Doc...ce/PrefabUtility.GetPrefabInstanceStatus.html

    Use
    GetPrefabInstanceStatus
    to determine if your object is a Prefab instance and use
    PrefabAssetType
    to then determine what kind of Prefab it is.

    Note that nested objects in a prefab asset will be also be Prefab instances.
     
  3. xeleh

    xeleh

    Joined:
    Jul 22, 2016
    Posts:
    302
    Is there any reason for PrefabUtility.GetPrefabAssetType() to return "NotAPrefab" for an open Prefab? That's what I am getting (in 2018.3b3) and this is the code I am using:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. namespace Betatesting {
    4.  
    5. public class Test : MonoBehaviour {
    6. }
    7.  
    8. }
    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3.  
    4. namespace Betatesting {
    5.  
    6. [CustomEditor(typeof(Test))]
    7. public class TestEditor : Editor {
    8.  
    9.     public override void OnInspectorGUI() {
    10.         Component component = serializedObject.targetObject as Component;
    11.         PrefabAssetType prefabType = PrefabUtility.GetPrefabAssetType(component);
    12.         EditorGUILayout.TextField("PrefabAssetType", prefabType.ToString());
    13.     }
    14.  
    15. }
    16.  
    17. }
    The results of this Test component when added to:
    • A plain GameObject: PrefabAssetType = NotAPrefab
    • A prefab Instance: PrefabAssetType = Regular
    • A prefab: PrefabAssetType = NotAPrefab
     
  4. SteenLund

    SteenLund

    Unity Technologies

    Joined:
    Jan 20, 2011
    Posts:
    639
  5. xeleh

    xeleh

    Joined:
    Jul 22, 2016
    Posts:
    302
    Thanks for the quick reply. I would argue that -by definition- a Prefab open in Prefab Mode has to be a Prefab, but I suppose you have reasons for treating it as a regular GameObject.

    Anyway my real concern is that I still need a way to differentiate a regular GameObject from an open Prefab. Is there any workaround for that (like knowing if an Inspector window is in Prefab Mode) or something?
     
  6. Mads-Nyholm

    Mads-Nyholm

    Unity Technologies

    Joined:
    Aug 19, 2013
    Posts:
    219
    Hi,

    Use the
    PrefabStageUtility
    :

    If you need to know if your GameObject is in Prefab Mode you can do:
    if (PrefabStageUtility.GetPrefabStage(yourGameObject) != null)


    or if you want to just know if Prefab Mode is currently active you can do
    if (PrefabStageUtility.GetCurrentPrefabStage() != null)


    Also check what properties you have on the returned
    PrefabStage
    object from those methods (root, prefabAssetPath etc.)
     
    LoneDev6, JanTuts and Ayrik like this.
  7. xeleh

    xeleh

    Joined:
    Jul 22, 2016
    Posts:
    302
    Exactly what I needed. It works like a charm. Thanks so much!
     
    Ayrik likes this.
  8. winxalex

    winxalex

    Joined:
    Jun 29, 2014
    Posts:
    166
    So how we change the code we have in previous versions:
    Code (CSharp):
    1. PrefabUtility.GetPrefabType(go)==PrefabType.Prefab
    with:
    Code (CSharp):
    1. PrefabUtility.IsPartOfAnyPrefab(lg.gameObject) && PrefabUtility.GetPrefabInstanceStatus(lg.gameObject) == PrefabInstanceStatus.NotAPrefab
    Code (CSharp):
    1. PrefabUtility.GetPrefabType(go)==PrefabType.PrefabInstance
    with:
    Code (CSharp):
    1. PrefabUtility.GetPrefabInstanceStatus(lg.gameObject) != PrefabInstanceStatus.NotAPrefab
    Code (CSharp):
    1. PrefabUtility.GetPrefabType(go)==PrefabType.None
    with:
    Code (CSharp):
    1.  
    2. !PrefabUtility.IsPartOfAnyPrefab(lg.gameObject)
    3.  
    ????
    Do you think this is optimal API design to find isPrefab, isPrefabInstance, isStandAlone?
     
    IanT, Alic and NelsonHurst like this.
  9. Tortuap

    Tortuap

    Joined:
    Dec 4, 2013
    Posts:
    137
    This API is so cryptic.

    PrefabUtility.GetPrefabInstanceStatus ( prefabObject ) returns PrefabInstanceStatus.NotAPrefab, with prefabObject being a prefab ( PrefabUtility.GetPrefabAssetType ( prefabObject ) returning PrefabAssetType.Regular ).

    Why not simply name it PrefabInstanceStatus.NotAnInstance ?
    PrefabInstanceStatus.NotAPrefab is a total nonsense imo.
     
  10. LuGus-Studios-Kasper

    LuGus-Studios-Kasper

    Joined:
    Apr 1, 2019
    Posts:
    1
    Agreed. This is very confusing. I just found this topic looking for an explanation on how something could simultaneously be NotAPrefab and a Regular prefab. To illustrate how seemingly absurd this API reads:

    Code (CSharp):
    1. if (PrefabUtility.GetPrefabInstanceStatus(selectedGameObject) == PrefabInstanceStatus.NotAPrefab && PrefabUtility.GetPrefabAssetType(selectedGameObject) != PrefabAssetType.NotAPrefab)
    2. {
    3.     Debug.Log ("This is a game object in the project view.");
    4. }
    Simply renaming the PrefabInstanceStatus enum value to "NotAnInstance" or "NotAPrefabInstance" would remove the confusion entirely.
     
  11. robot-ink

    robot-ink

    Joined:
    Jul 1, 2011
    Posts:
    18
    Agree completely here. if you want to check for an un-instantiated prefab the code is

    Code (CSharp):
    1. objectType != PrefabAssetType.NotAPrefab &&
    2. prefabInstanceStatus == PrefabInstanceStatus.NotAPrefab;
    confusing.

    `NotAnInstance` would be much better InstanceStatus
     
    winxalex and PowerhoofDave like this.
  12. The_MrX_

    The_MrX_

    Joined:
    Aug 25, 2019
    Posts:
    12
    Dear god unity, why not just a builtin .IsNotAnInstance that also automatically checks that we aren't in the prefab editor???(shouldn't take into account nested prefabs at all in the decision, since that is just extremely confusing for a bool, use enums returns for nested prefabs conditional checks)

    Seems like such an obvious basic solution to something that is going to used quite often.

    The 2 bool return methods below, change far too much depending on multiple factors, to the point they should just return enums or be separated into multiple versions.

    https://docs.unity3d.com/ScriptReference/PrefabUtility.IsOutermostPrefabInstanceRoot.html
    https://docs.unity3d.com/ScriptReference/PrefabUtility.IsAnyPrefabInstanceRoot.html
     
  13. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,933
    In 2020, the Obsolete tag on "PrefabUtility.GetPrefabType" is still pointing people to use the wrong API calls. Such a mess.

    For checking instance, asset, etc, I eventually realised there's now (Who knows when this got added? Unity doesn't document API changes :( ):

    "PrefabUtility.IsPartOfPrefabAsset" -- which gives the simple result I needed.
     
  14. noio

    noio

    Joined:
    Dec 17, 2013
    Posts:
    232
    I have also seen the method of
    gameObject.scene.name == null
    , but that can't possibly be a recommended way for checking if you have a reference to the Prefab vs an instance?
     
    Last edited: Apr 23, 2020
  15. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,933
    Since there are now dedicated API calls for this, with detailed options, I would say it's extremely foolish to use a hack like that instead. Especially considering how many serious bugs the scenemanager classes shipped with and continue to have :).

    And not least: how is that going to tell you about things like stage vs scene vs prefab vs nested prefab vs disconnected prefab ... etc?
     
  16. noio

    noio

    Joined:
    Dec 17, 2013
    Posts:
    232
    I agree. That is what I was saying. I can't imagine having to use it.

    However: I was confused. I was actually so confused by the name
    NotAPrefab
    , that I thought it was not possible at all with the dedicated API to find out if a reference is an "asset" or "uninstantiated" prefab.
    NotAPrefab
    sounds like the exact opposite of what I was trying to find out.

    Anyway. I should have read the thread better because @robot-ink 's code does give the desired result.
     
  17. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    Well, its fast and dirty way to check if its an actual asset, that is not being modified or in the scene.
    Which is really useful sometimes.

    Also, it can be simplified to:
    Code (CSharp):
    1. gameObject.scene == default
     
    FlightOfOne and Invertex like this.
  18. noio

    noio

    Joined:
    Dec 17, 2013
    Posts:
    232
    I found myself returning to this issue because now I'm trying to do the same thing at runtime.

    In that case, is the
    gameObject.scene
    method actually the only way?
     
  19. SteenLund

    SteenLund

    Unity Technologies

    Joined:
    Jan 20, 2011
    Posts:
    639
    @noio

    If *at runtime* you mean in a standalone player, then yes. All prefab information is stripped away in the players and all you have is a collection of GameObjects in an asset
     
    Alic likes this.