- Home /
How to highlight an object in the heirarchy from code?
I have an editor script that finds objects in the scene which reference the currently selected object, adds them to a List and then sets Selection.objects to those objects:
foreach (UnityObject sceneObject in sceneObjects)
{
// Iterate over the fields in the object
FieldInfo[] fInfos = sceneObject.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
bool addedObjectToReferences = false;
foreach (FieldInfo fInfo in fInfos)
{
bool fieldReferencesValue = false;
SysObject fieldValue = fInfo.GetValue(sceneObject);
if (fieldValue == selection)
{
fieldReferencesValue = true;
}
else if (fInfo.FieldType.IsArray && fInfo.FieldType.GetElementType().IsAssignableFrom(selectionType))
{
// This is an array field, check each of it's elements for a reference
foreach (System.Object element in (System.Object[]) fieldValue)
{
if (element == selection)
{
fieldReferencesValue = true;
break;
}
}
}
if (fieldReferencesValue)
{
if (!addedObjectToReferences)
{
EditorGUIUtility.PingObject(sceneObject);
references.Add(sceneObject);
addedObjectToReferences = true;
}
// Log with context for easy use
Log.Log(string.Format("{0} referenced by {1} ({2}.{3})", selection, sceneObject.name, sceneObject.GetType().Name, fInfo.Name), sceneObject);
}
}
}
if (references.Count == 0)
{
EditorUtility.DisplayDialog("No references", "No references found to selection", "Ok");
}
else
{
Log.Log(string.Format("Found {0} references to {1}", references.Count, selection.name));
Selection.objects = references.ToArray();
}
For the most part this works beautifully, the references are found and selected (I can tell they are selected by the content of the inspector), but they are not hilighted in the Hierarchy. Am I missing something here? Is there some way to force the editor to highlight the current selection(s)?
Answer by DavidDebnar · Jul 10, 2013 at 10:43 AM
Edit: I just reread your question. Make sure to pass GameObject[] into Selection.objects, not Object[] and it'll work.
Also, take a look at EditorGUIUtility.PingObject.
function Ping() {
if(!Selection.activeObject) {
Debug.LogError("Select an object to ping");
return;
}
for(var o in Selection.objects) {
EditorGUIUtility.PingObject(o);
Debug.Log("Pinged " + o.name);
}
}
--David--
Thanks $$anonymous$$, I'm already pinging the objects (line 30 in the code I posted) and that works to temporarily highlight the objects. However I want to persistently highlight them (as if they had been selected with a click).
Thanks, but nope, passing it a GameObject array ins$$anonymous$$d of a Unity.Object array makes no difference (not that I would have expected it to, the property is a Unity.Object[] type so they would be doing casting internally if necessary anyway, and things like textures and materials wouldn't be selectable if a GO[] was required). For reference, here's the change I tried (after trying a linq version first, just to be sure my linq isn't completely fubar):
List<GameObject> goReferences = new List<GameObject>();
foreach (UnityObject reference in references)
{
if (reference is GameObject) goReferences.Add(reference as GameObject);
}
Selection.objects = goReferences.ToArray();
Answer by Free286 · Mar 22, 2018 at 11:24 AM
Modified script to work by pressing D when selecting an object in the hierarchy. It will find and highlight objects that are referencing the selected objects.
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEditor;
using UnityEngine;
public class BacktraceReference {
private Component _theObject;
public static List<UnityEngine.Object> find;
[MenuItem("Tools/What Objects Reference this? _d")]
public static void FindReferences() {
find = new List<UnityEngine.Object>();
foreach (var item in Selection.objects) {
var g = item as GameObject;
if (g) {
foreach (var c in g.GetComponents<Component>()) {
FindObjectsReferencing(c);
}
}
}
if (find.Count == 0) {
// Debug.Log("<b>No objects reference this</b>");
}
else {
Selection.objects = find.ToArray();
}
foreach (var o in Selection.objects) {
EditorGUIUtility.PingObject(o);
}
}
private static void FindObjectsReferencing<T>(T mb) where T : Component {
var objs = Resources.FindObjectsOfTypeAll(typeof (Component)) as Component[];
if (objs == null) return;
foreach (Component obj in objs) {
FieldInfo[] fields =
obj.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance |
BindingFlags.Static);
foreach (FieldInfo fieldInfo in fields) {
if (FieldReferencesComponent(obj, fieldInfo, mb)) {
var contains = false;
foreach (var item in Selection.objects) {
if (item == obj.gameObject) {
contains = true;
break;
}
}
contains |= find.Contains(obj.gameObject);
if (!contains) {
find.Add(obj.gameObject);
Debug.Log("<b>" + obj.gameObject + "</b>\n", obj.gameObject);
}
}
}
}
}
private static bool FieldReferencesComponent<T>(Component obj, FieldInfo fieldInfo, T mb) where T : Component {
if (fieldInfo.FieldType.IsArray) {
var arr = fieldInfo.GetValue(obj) as Array;
if (arr != null) {
foreach (object elem in arr) {
if (elem != null && mb != null && elem.GetType() == mb.GetType()) {
var o = elem as T;
if (o == mb)
return true;
}
}
}
}
else {
if (fieldInfo.FieldType == mb.GetType()) {
var o = fieldInfo.GetValue(obj) as T;
if (o == mb)
return true;
}
}
return false;
}
}
Your answer
Follow this Question
Related Questions
Copying files from one directory to the other 1 Answer
Is it possible to draw more than one property attribute on a field? 1 Answer
Browse button in unity editor script 0 Answers
Find public assigned values using editor script 1 Answer
How can I preserve static object/data between editor and play? 2 Answers