code

Auto fills specific components fields

Hello again guys!

So, after reading through some feedback entries, I stumbled across this one:
https://feedback.unity3d.com/suggestions/automatically-inject-requirecomponent-fields

I thought that this was a wonderful idea, what it basically is auto fills component fills marked with the attribute RequireComponent, it not only adds (if there is not) the component in the gameobject, it also fills a specific field which was marked with that attribute. So I decided to implement this myself. Of course, the component must be serialized to work, this means that the component must be expanded and the inspector cannot be in debug mode, it also will not work with abstract class components like Collider, it must be a CapsuleCollider, BoxCollider, etc.

Here are the scripts:

This one goes in an Editor folder:

using UnityEngine;
using UnityEditor;

[CustomPropertyDrawer(typeof(RequiredComponentAttribute))]
public class RequiredComponentDrawer : PropertyDrawer
{
	public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
	{
		EditorGUI.PropertyField(position, property);

		MonoBehaviour mono = property.serializedObject.targetObject as MonoBehaviour;
		if (typeof(Component).IsAssignableFrom(fieldInfo.FieldType))
		{
			if (property.objectReferenceValue == null)
			{
				Component comp = mono.GetComponent(fieldInfo.FieldType);

				if (comp == null)
				{
					comp = mono.gameObject.AddComponent(fieldInfo.FieldType);
				}

				property.objectReferenceValue = comp;

				Undo.RecordObject(mono.gameObject, "Add/Set Components to " + mono.gameObject.name);
			}
		}
		else
		{
			Debug.LogError("Field <b>" + fieldInfo.Name + "</b> of " + mono.GetType() + " is not a component!", mono);
		}
	}
}

And this one goes in any folder:

using UnityEngine;
public class RequiredComponentAttribute : PropertyAttribute
{
}

Yes, I like to keep attributes in a separate script, even if they are just a stub.

Thanks for reading, let me know if you can optimize it or add something to it.

Cheers,
Rodolfo Rubens

Preview Main Component Icon In Hierachy

Hey guys,
I made a simple script that shows the icon of the first component (after transform of course) of the gameobject in hierarchy and also show a toggle to toggle the active state of the object.
It can also show custom component icons, you just need to put them in Assets/Editor/Icons.
Also, it has some “smart” icon showing that shows differently depending if the object has components or not and if it has childs or not, if it’s a prefab or not too:
Plus:
– Mass deactivate/activate gameobject and its children by holding alt and clicking on its toggle.
ps.: The children will inherit the toggled object’s active state, IT WILL NOT TOGGLE THE CHILD ACTIVE STATE.
– Choose to only show specific component types and etc.
– If custom component type was added to the specific component types and there is no icon for it, it will show a gameobject icon
Here is the code:
// Main Component Icon, Active State Toggling and "Smart Empty Object Icon Display"
using UnityEditor;
using UnityEngine;
using System;
using System.Collections.Generic;

[InitializeOnLoad]
class MainComponentIcon
{
	// only show these types if showAllTypes is false
	static Type[] componentTypes = new Type[]
	{
		typeof(Light),
		typeof(BoxCollider),
		typeof(Camera),
		typeof(ParticleSystem),
		typeof(TrailRenderer),
		typeof(MeshRenderer),
		typeof(MeshFilter),
		typeof(SpriteRenderer),
		typeof(AudioSource),
		typeof(Canvas),
		typeof(CanvasGroup),
		typeof(UnityEngine.UI.Image),
		typeof(UnityEngine.UI.Button),
		typeof(UnityEngine.UI.Text),

		// must add the custom types here if showAllTypes is false
		typeof(GameController),
		typeof(PlayerController),
		typeof(SpellScript)
	};
	static bool showActiveToggle = true;
	static bool showIndentedActiveToggle = true;
	static bool showAllTypes = true;
	static bool useFallbackIconForExcludedComponents = false;
	static bool prefabOverOthers = true; // don't show any component icon if the gameobject is a prefab, show the prefab icon instead
	static bool alwaysShowCustom = false; // will show all custom, even if they don't have custom images (will show the little script page icon)
	static bool alwaysShowPrefabContainer = true;
	static IdleObjectsView showEmptyPrefabIconInIdleObjects = IdleObjectsView.TransformIcon; // // gameobjects with no child or components
	static FallbackIcon fallbackIcon = FallbackIcon.GameObjectOrTransformsOrPrefab;

	// UI exceptions
	static bool canvasOverPrefab = true;

	static List<GameObject> allChildGOsForToggle;
	static bool toggleActiveAllChildInheritToggleObject = true; // Attention: if hold alt and clickin on object toggle, it will set all childs active state to the same of the clicked object

	static MainComponentIcon()
	{
		// Init
		EditorApplication.hierarchyWindowItemOnGUI += HierarchyItemCB;
	}

	static void HierarchyItemCB(int instanceID, Rect selectionRect)
	{
		GameObject obj = EditorUtility.InstanceIDToObject(instanceID) as GameObject;
		var backupColor = GUI.color;

		if (obj)
		{
			Rect r = new Rect(selectionRect);
			if (showActiveToggle)
			{
				// Toggle active button
				r.x = showIndentedActiveToggle ? selectionRect.x - 28 : 2;
				r.width = 18;
				r.height = 16;

				EditorGUI.BeginChangeCheck();

				backupColor = GUI.color;
				if (!obj.activeInHierarchy && obj.transform.parent != null) GUI.color = new Color(GUI.color.r, GUI.color.g, GUI.color.b, 0.5f);
				var toggleValue = GUI.Toggle(r, obj.activeSelf, "");
				GUI.color = backupColor;
				if (toggleActiveAllChildInheritToggleObject && Event.current.alt)
				{
					if (EditorGUI.EndChangeCheck())
					{
						if (allChildGOsForToggle == null) allChildGOsForToggle = new List<GameObject>();
						allChildGOsForToggle.Clear();
						allChildGOsForToggle.Add(obj);
						FetchAllChildGameObjects(obj.transform);
						Undo.RecordObjects(allChildGOsForToggle.ToArray(), "Toggle GameObjects Active");
						allChildGOsForToggle.ForEach(child => child.SetActive(toggleValue));
					}
				}
				else
				{
					if (EditorGUI.EndChangeCheck())
					{
						Undo.RecordObject(obj, "Toggle " + obj.name + " Active");
						obj.SetActive(toggleValue);
					}
				}
			}

			// Icon
			r.x = EditorGUIUtility.currentViewWidth - 38;
			r.width = 18;
			r.height = 18;
			backupColor = GUI.color;
			if (!obj.activeInHierarchy) GUI.color = new Color(GUI.color.r, GUI.color.g, GUI.color.b, 0.5f);
			var components = obj.GetComponents<Component>();
			if (components != null)
			{
				// FIRST COMPONENT IS ALWAYS TRANSFORM OR RECT TRASNFORM
				if (components.Length > 1)
				{
					// HAS COMPONENTS
					Type type = components[1].GetType();
					Texture image = EditorGUIUtility.ObjectContent(null, type).image;
					bool isInComponentTypesList = Array.Exists(componentTypes, x => x == type);

					if (image == null)
					{
						// put your custom components icons in Assets/Editor/Icons, name it the same name of your class and change the extension below as accordingly
						image = AssetDatabase.LoadAssetAtPath("Assets/Editor/Icons/" + type.ToString() + ".psd", typeof(Texture)) as Texture;
					}

					if (canvasOverPrefab && type == typeof(Canvas))
					{
						GUI.Label(r, EditorGUIUtility.IconContent("Canvas Icon"));
					}
					else if (prefabOverOthers && CanShowAsPrefab(obj))
					{
						ShowFallbackIcon(obj, r);
					}
					else if (!image && alwaysShowCustom)
					{
						GUI.Label(r, EditorGUIUtility.IconContent("cs Script Icon"));
					}
					else if (showAllTypes || isInComponentTypesList)
					{
						if (image)
						{
							GUI.Label(r, image);
						}
						else
						{
							ShowFallbackIcon(obj, r);
						}
					}
					else if (image && useFallbackIconForExcludedComponents || alwaysShowPrefabContainer && CanShowAsPrefab(obj))
					{
						ShowFallbackIcon(obj, r);
					}
				}
				else
				{
					// IDLE OBJECTS
					if (obj.transform.childCount == 0)
					{
						if (CanShowAsPrefab(obj))
							GUI.Label(r, EditorGUIUtility.IconContent("PrefabNormal Icon"));
						else if (showEmptyPrefabIconInIdleObjects == IdleObjectsView.WhitePrefabIcon) // no child nor components
							GUI.Label(r, EditorGUIUtility.IconContent("Prefab Icon"));
						else if (showEmptyPrefabIconInIdleObjects == IdleObjectsView.TransformIcon) // no child nor components
						{
							if (obj.GetComponent<RectTransform>())
								GUI.Label(r, EditorGUIUtility.IconContent("RectTransform Icon"));
							else
								GUI.Label(r, EditorGUIUtility.IconContent("Transform Icon"));
						}
					}
					// NO COMPONENTS BUT HAS CHILDREN
					else if (obj.transform.childCount > 0)
					{
						if (CanShowAsPrefab(obj))
							GUI.Label(r, EditorGUIUtility.IconContent("PrefabNormal Icon"));
						else
							GUI.Label(r, EditorGUIUtility.IconContent("Prefab Icon"));

						GUI.Label(r, EditorGUIUtility.IconContent("Transform Icon"));
					}

				}
			}

			GUI.color = backupColor;
		}
	}

	static void ShowFallbackIcon(GameObject obj, Rect r)
	{
		switch (fallbackIcon)
		{
			case FallbackIcon.TransformOrRect:

				if (obj.GetComponent<RectTransform>())
					GUI.Label(r, EditorGUIUtility.IconContent("RectTransform Icon"));
				else
					GUI.Label(r, EditorGUIUtility.IconContent("Transform Icon"));
				break;

			case FallbackIcon.GameObjectOrPrefab:
				if (CanShowAsPrefab(obj))
					GUI.Label(r, EditorGUIUtility.IconContent("PrefabNormal Icon"));
				else
					GUI.Label(r, EditorGUIUtility.IconContent("GameObject Icon"));
				break;

			case FallbackIcon.GameObjectOrTransformsOrPrefab:
				if (CanShowAsPrefab(obj))
					GUI.Label(r, EditorGUIUtility.IconContent("PrefabNormal Icon"));
				else
				{
					if (obj.GetComponents<Component>().Length > 1)
					{
						GUI.Label(r, EditorGUIUtility.IconContent("GameObject Icon"));
					}
					else
					{
						GUI.Label(r, EditorGUIUtility.IconContent("Transform Icon"));
					}
				}
				break;
		}
	}

	static bool IsPartOfPrefab(GameObject prefab)
	{
		return PrefabUtility.GetPrefabParent(prefab) != null;
	}

	static bool IsPrefabParent(GameObject prefab)
	{
		return PrefabUtility.FindPrefabRoot(prefab) == prefab;
	}

	static bool CanShowAsPrefab(GameObject prefab)
	{
		if (IsPrefabParent(prefab) &&
			IsPartOfPrefab(prefab) &&
			PrefabUtility.GetPrefabType(prefab) == PrefabType.PrefabInstance ||
			PrefabUtility.GetPrefabType(prefab) == PrefabType.ModelPrefabInstance)
		{
			return true;
		}

		return false;
	}

	public static void FetchAllChildGameObjects(Transform transform)
	{
		if (allChildGOsForToggle == null) allChildGOsForToggle = new List<GameObject>();
		foreach (Transform t in transform)
		{
			if (!allChildGOsForToggle.Contains(t.gameObject)) allChildGOsForToggle.Add(t.gameObject);
			FetchAllChildGameObjects(t);
		}
	}

	//static bool
}

enum FallbackIcon
{
	None,
	GameObjectOrTransformsOrPrefab,
	GameObjectOrPrefab,
	TransformOrRect
}

enum IdleObjectsView
{
	None,
	TransformIcon,
	WhitePrefabIcon
}

I hope you enjoy!