In short
I want two functions:
- Is input GameObject in a prefab asset (in Project or prefab editor)?
- Is input GameObject in a prefab instance (in scene but not prefab editor)?
Details
I like to do validation on my objects, but I don’t understand how to do it with the new prefab system. I need to be able to check whether an object is a prefab instance/asset from OnValidate (to ignore missing data that’d be filled on an instance or skip adding scene-specific data on assets), so I want two kinds of validation:
- validate objects in the prefab editor (prefab assets)
- validate objects in the scene (prefab instances)
Research
I wrote some code (below) to print the object, the scene, and what seemed like relevant PrefabUtility calls.
From prefab editor editing “Sphere”:
'Sphere' Sphere AnyPrefab=False PrefabAsset=False PrefabInstance=False NonAssetPrefabInstance=False is_stage_scene= True NotAPrefab None
'Sphere' AnyPrefab=False PrefabAsset=False PrefabInstance=False NonAssetPrefabInstance=False is_stage_scene=False NotAPrefab None
'Sphere' AnyPrefab=False PrefabAsset=False PrefabInstance=False NonAssetPrefabInstance=False is_stage_scene=False NotAPrefab None
'Sphere' AnyPrefab= True PrefabAsset= True PrefabInstance=False NonAssetPrefabInstance=False is_stage_scene=False Regular Prefab
'Sphere' Gameplay AnyPrefab= True PrefabAsset=False PrefabInstance= True NonAssetPrefabInstance= True is_stage_scene=False Regular PrefabInstance
From my “Gameplay” scene:
'Sphere' Gameplay AnyPrefab= True PrefabAsset=False PrefabInstance= True NonAssetPrefabInstance= True is_stage_scene=False Regular PrefabInstance
Presumably touching a prefab in the prefab editor will trigger validation in
the scene, so that explains the “Gameplay” result from prefab editor. Clicking
the IsPartOfAnyPrefab=True result without a scene reveals the asset in my
Project tab.
I don’t understand the other things with no scene.
We can distinguish three cases:
scene: AnyPrefab= True PrefabAsset=False PrefabInstance= True NonAssetPrefabInstance= True is_stage_scene=False Regular PrefabInstance
asset: AnyPrefab= True PrefabAsset= True PrefabInstance=False NonAssetPrefabInstance=False is_stage_scene=False Regular Prefab
editor: AnyPrefab=False PrefabAsset=False PrefabInstance=False NonAssetPrefabInstance=False is_stage_scene= True NotAPrefab None
It seems that GetPrefabAssetType is an unreliable way to tell prefab assets
from instances and not as useful as the deprecated GetPrefabType. Instead, we
must check multiple things:
bool is_prefab_instance = IsPartOfAnyPrefab(obj) && !IsPartOfPrefabAsset(obj) && IsPartOfNonAssetPrefabInstance(obj)
bool is_prefab_asset = IsPartOfAnyPrefab(obj) && IsPartOfPrefabAsset(obj) && !IsPartOfNonAssetPrefabInstance(obj)
var stage = UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage();
bool is_prefab_editor = stage != null && stage.scene == obj.scene;
Is there a simpler way to detect prefabs in the prefab editor? Are there flaws with my approach?
Code I’m using:
using UnityEngine;
using UnityEditor;
public class WhatIsPrefab : MonoBehaviour
{
public bool ToggleToValidate;
void OnValidate()
{
var stage = UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage();
bool is_stage_scene = stage != null && stage.scene == gameObject.scene;
Debug.Log(string.Format("'{0}' {1,10} AnyPrefab={2,5} PrefabAsset={3,5} PrefabInstance={4,5} NonAssetPrefabInstance={5,5} is_stage_scene={6,5} {7} {8}",
name,
gameObject.scene.name,
PrefabUtility.IsPartOfAnyPrefab(gameObject),
PrefabUtility.IsPartOfPrefabAsset(gameObject),
PrefabUtility.IsPartOfPrefabInstance(gameObject),
PrefabUtility.IsPartOfNonAssetPrefabInstance(gameObject),
is_stage_scene,
PrefabUtility.GetPrefabAssetType(gameObject),
PrefabUtility.GetPrefabType(gameObject)), // deprecated, but just in case
this);
}
}