Skip to main content
Adding AddComponentMenu trick
Source Link
DMGregory
  • 136.3k
  • 22
  • 247
  • 373

Here's a cheeky workaround you can use.

First we define an empty struct, so it doesn't actually increase the memory allocation of our components:

[System.Serializable]
public struct NamespaceHint 
{
}

Then we give it a PropertyDrawer (placed in a folder called "Editor") that prints out the fully-qualified name of the component it's attached to:

[CustomPropertyDrawer(typeof(NamespaceHint))]
public class NamespaceHintDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        var t = property.serializedObject.targetObject.GetType();        
        EditorGUI.LabelField(position, t.FullName);
    }
}

Then for any type that's ambiguous, we can add a little hint at the top of the inspector:

namespace Player
{
    public class Controller : MonoBehaviour
    {
        [SerializeField] NamespaceHint _ns;

        // ... other members...
    }
}

And now two identical components in different namespaces are distinguishable in the Inspector - though you still have to guess and check when selecting them from the Add Component menu:

Two controller components, one labelled "Enemy.Controller", one "Player.Controller".

You could also do this manually with a [Header("Player.Controller")] attribute if you don't need it to automatically adapt to name changes.

Unfortunately, you still have to guess and check when selecting them from the Add Component menu:

Two controller components, one labelled "Enemy.Controller", one "Player.Controller"

To fix that, you can add an AddComponentMenu attribute to the top of your class to change its label/sorting in the add component menu:

[AddComponentMenu("Scripts/Player Controller")]
public class Controller : MonoBehaviour {
// ...

Add Component menu with unique component names

...but that one would need manual updates if you change your naming scheme.


But note how much better this looks and how much easier we can get it if we just give classes unique names to begin with:

namespace Player {
    public class PlayerController : MonoBehaviour {
    // ...

Same example, but with classes named EnemyController and PlayerController

Boom. We can tell them apart in the inspector and component selection menu, and we don't need thisany extra boilerplate at the top of the script, so it's even less to type! The only downside is a slightly longer component name / more redundant-looking fully qualified name to reference in scripts: Player.PlayerController.

Here's a cheeky workaround you can use.

First we define an empty struct, so it doesn't actually increase the memory allocation of our components:

[System.Serializable]
public struct NamespaceHint 
{
}

Then we give it a PropertyDrawer (placed in a folder called "Editor") that prints out the fully-qualified name of the component it's attached to:

[CustomPropertyDrawer(typeof(NamespaceHint))]
public class NamespaceHintDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        var t = property.serializedObject.targetObject.GetType();        
        EditorGUI.LabelField(position, t.FullName);
    }
}

Then for any type that's ambiguous, we can add a little hint at the top of the inspector:

namespace Player
{
    public class Controller : MonoBehaviour
    {
        [SerializeField] NamespaceHint _ns;

        // ... other members...
    }
}

And now two identical components in different namespaces are distinguishable in the Inspector - though you still have to guess and check when selecting them from the Add Component menu:

Two controller components, one labelled "Enemy.Controller", one "Player.Controller"

You could also do this manually with a [Header("Player.Controller")] attribute if you don't need it to automatically adapt to name changes.


But note how much better this looks if we just give classes unique names to begin with:

Same example, but with classes named EnemyController and PlayerController

Boom. We can tell them apart in the component selection menu and we don't need this boilerplate at the top of the script, so it's even less to type!

Here's a cheeky workaround you can use.

First we define an empty struct, so it doesn't actually increase the memory allocation of our components:

[System.Serializable]
public struct NamespaceHint 
{
}

Then we give it a PropertyDrawer (placed in a folder called "Editor") that prints out the fully-qualified name of the component it's attached to:

[CustomPropertyDrawer(typeof(NamespaceHint))]
public class NamespaceHintDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        var t = property.serializedObject.targetObject.GetType();        
        EditorGUI.LabelField(position, t.FullName);
    }
}

Then for any type that's ambiguous, we can add a little hint at the top of the inspector:

namespace Player
{
    public class Controller : MonoBehaviour
    {
        [SerializeField] NamespaceHint _ns;

        // ... other members...
    }
}

And now two identical components in different namespaces are distinguishable in the Inspector.

You could also do this manually with a [Header("Player.Controller")] attribute if you don't need it to automatically adapt to name changes.

Unfortunately, you still have to guess and check when selecting them from the Add Component menu:

Two controller components, one labelled "Enemy.Controller", one "Player.Controller"

To fix that, you can add an AddComponentMenu attribute to the top of your class to change its label/sorting in the add component menu:

[AddComponentMenu("Scripts/Player Controller")]
public class Controller : MonoBehaviour {
// ...

Add Component menu with unique component names

...but that one would need manual updates if you change your naming scheme.


But note how much better this looks and how much easier we can get it if we just give classes unique names to begin with:

namespace Player {
    public class PlayerController : MonoBehaviour {
    // ...

Same example, but with classes named EnemyController and PlayerController

Boom. We can tell them apart in the inspector and component selection menu, and we don't need any extra boilerplate at the top of the script, so it's even less to type! The only downside is a slightly longer component name / more redundant-looking fully qualified name to reference in scripts: Player.PlayerController.

Source Link
DMGregory
  • 136.3k
  • 22
  • 247
  • 373

Here's a cheeky workaround you can use.

First we define an empty struct, so it doesn't actually increase the memory allocation of our components:

[System.Serializable]
public struct NamespaceHint 
{
}

Then we give it a PropertyDrawer (placed in a folder called "Editor") that prints out the fully-qualified name of the component it's attached to:

[CustomPropertyDrawer(typeof(NamespaceHint))]
public class NamespaceHintDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        var t = property.serializedObject.targetObject.GetType();        
        EditorGUI.LabelField(position, t.FullName);
    }
}

Then for any type that's ambiguous, we can add a little hint at the top of the inspector:

namespace Player
{
    public class Controller : MonoBehaviour
    {
        [SerializeField] NamespaceHint _ns;

        // ... other members...
    }
}

And now two identical components in different namespaces are distinguishable in the Inspector - though you still have to guess and check when selecting them from the Add Component menu:

Two controller components, one labelled "Enemy.Controller", one "Player.Controller"

You could also do this manually with a [Header("Player.Controller")] attribute if you don't need it to automatically adapt to name changes.


But note how much better this looks if we just give classes unique names to begin with:

Same example, but with classes named EnemyController and PlayerController

Boom. We can tell them apart in the component selection menu and we don't need this boilerplate at the top of the script, so it's even less to type!