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:
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 {
// ...
...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 {
// ...
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
.