I’m trying to use an editor script to determine if MonoBehaviour field points to a prefab.
I add a Transform field to a MonoBehaviour.
The MonoBehaviour script is added to a gameobject.
I drag and drop the prefab on on the gameobject’s public field.
This makes the public field point to the prefab Transform.
And now I want to make sure that the Transform field on the game object is the same as the prefab Transform.
What is the best way to see if a meta reference points at a prefab?
Attached repro project.
822934–30517–$PrefabTest.zip (30.7 KB)
And I found the answer reflecting on some undocumented 3.5 features.
It comes down to PrefabUtility.
Specifically PrefabUtility.GetPrefabObject() which returns a Prefab object that’s not exposed in script.
So I was able to reflect on it’s methods and get the objects by type “Transform” which let’s me finally pair up a Scene transform with the original prefab transform.
using System.Reflection;
using UnityEditor;
using UnityEngine;
public class MenuCheckReference : MonoBehaviour
{
[MenuItem("Assets/Check Prefab Reference")]
public static void CheckReference()
{
GameObject go = GameObject.Find("PrefabReference");
if (null == go)
{
Debug.LogError("Failed to get game object reference to Prefab Reference");
return;
}
Transform prefabTransform = (Transform)Resources.LoadAssetAtPath("Assets/MyPrefab.prefab", typeof(Transform));
if (null == prefabTransform)
{
Debug.LogError("Failed to get prefab transform");
}
Debug.Log("End of prefab fields");
Debug.Log (string.Format("go prefab type: {0}", PrefabUtility.GetPrefabType(go.transform)));
Debug.Log (string.Format("prefabTransform prefab type: {0}", PrefabUtility.GetPrefabType(prefabTransform)));
Debug.Log (string.Format("go instance id: {0}", PrefabUtility.GetPrefabParent(go.transform).GetInstanceID()));
Debug.Log (string.Format("prefabTransform instance id : {0}", PrefabUtility.GetPrefabParent(prefabTransform).GetInstanceID()));
if (go.transform == prefabTransform)
{
Debug.Log("Prefab transform matches!");
}
else
{
Debug.LogError("Prefab transform does not match!");
}
if (null == PrefabUtility.GetPrefabParent(go.transform))
{
Debug.LogError("go prefab parent name: (null)");
}
else
{
Debug.Log (string.Format("go prefab parent name: {0}", PrefabUtility.GetPrefabParent(go.transform).name));
}
if (null == PrefabUtility.GetPrefabParent(prefabTransform))
{
Debug.LogError("go prefab parent name: (null)");
}
else
{
Debug.Log (string.Format("prefabTransform parent object name: {0}", PrefabUtility.GetPrefabParent(prefabTransform).name));
}
if (PrefabUtility.GetPrefabParent(go.transform) == PrefabUtility.GetPrefabParent(prefabTransform))
{
Debug.Log("Prefab parent transform matches!");
}
else
{
Debug.LogError("Prefab parent transform does not match!");
}
if (null == PrefabUtility.GetPrefabObject(go.transform))
{
Debug.LogError("go prefab object name: (null)");
}
else
{
Debug.Log (string.Format("go prefab object name: {0}", PrefabUtility.GetPrefabObject(go.transform).name));
}
if (null == PrefabUtility.GetPrefabObject(prefabTransform))
{
Debug.LogError("prefabTransform prefab object name: (null)");
}
else
{
Debug.Log (string.Format("prefabTransform prefab object name: {0}", PrefabUtility.GetPrefabObject(prefabTransform).name));
}
if (PrefabUtility.GetPrefabObject(go.transform) == PrefabUtility.GetPrefabObject(prefabTransform))
{
Debug.Log("Prefab object transform matches!");
}
else
{
Debug.LogError("Prefab object transform does not match!");
}
if (go.transform == PrefabUtility.GetPrefabObject(prefabTransform))
{
Debug.Log("Prefab transform matches!");
}
else
{
Debug.LogError("Prefab transform does not match!");
}
// and finally the code I was looking for!!!!
UnityEngine.Object prefab = PrefabUtility.GetPrefabObject(prefabTransform);
foreach (FieldInfo fi in prefab.GetType().GetFields())
{
Debug.Log(string.Format("Field: {0}", fi.Name));
}
foreach (PropertyInfo pi in prefab.GetType().GetProperties())
{
Debug.Log(string.Format("Property: {0}", pi.Name));
}
foreach (MethodInfo mi in prefab.GetType().GetMethods())
{
//Debug.Log(string.Format("Method: {0}", mi.Name));
if (mi.Name.Equals("FindObjectsOfType"))
{
UnityEngine.Object[] objects = (UnityEngine.Object[])mi.Invoke(prefab, new object[] { typeof(Transform) });
foreach (UnityEngine.Object obj in objects)
{
Transform t = (Transform)obj;
Debug.Log (obj.ToString());
if (t == go.transform)
{
Debug.Log ("FINALLY matched the gameobject transform to the prefab transform");
}
}
}
}
}
}
Cleaned up the code:
using System.Reflection;
using UnityEditor;
using UnityEngine;
public class MenuCheckReference : MonoBehaviour
{
[MenuItem("Assets/Check Prefab Reference")]
public static void CheckReference()
{
GameObject go = GameObject.Find("PrefabReference");
if (null == go)
{
Debug.LogError("Failed to get game object reference to Prefab Reference");
return;
}
NewBehaviourScript script = go.GetComponent<NewBehaviourScript>();
if (null == script)
{
return;
}
UnityEngine.Object prefabAsset = AssetDatabase.LoadAssetAtPath("Assets/MyPrefab.prefab", typeof(UnityEngine.Object));
if (null == prefabAsset)
{
Debug.LogError("Failed to get prefab asset");
return;
}
UnityEngine.Object otherAsset = AssetDatabase.LoadAssetAtPath("Assets/OtherPrefab.prefab", typeof(UnityEngine.Object));
if (null == otherAsset)
{
Debug.LogError("Failed to get other asset");
return;
}
// UnityEngine.Component GetComponent(System.Type)
MethodInfo mi;
mi = prefabAsset.GetType().GetMethod("GetComponent", new [] {typeof(System.Type)});
if (mi.Name.Equals("GetComponent"))
{
try
{
Transform t = (Transform) mi.Invoke(prefabAsset, new object[] { typeof(Transform) } );
if (script.MyPrefab == t)
{
Debug.Log ("Prefab Asset");
}
}
catch (System.Exception)
{
}
}
mi = otherAsset.GetType().GetMethod("GetComponent", new [] {typeof(System.Type)});
if (mi.Name.Equals("GetComponent"))
{
try
{
Transform t = (Transform) mi.Invoke(otherAsset, new object[] { typeof(Transform) } );
if (script.MyPrefab == t)
{
Debug.Log ("Other Asset");
}
}
catch (System.Exception)
{
}
}
}
}
The check can only be done at edit time. Not at runtime. But the references could be saved in a collection for comparison at runtime.