public class InspectorDecoratorEditor : Editor
{
public static readonly System.Type EndType = typeof(UnityEngine.MonoBehaviour); // end type dont need show in inspector
public static readonly System.Type BaseEditorType = typeof(UnityEditor.Editor); // CustomEditor must inherit from it, filter
public static readonly BindingFlags CustomEditorFieldFlags = BindingFlags.NonPublic | BindingFlags.Instance; // flag
// type cache[Assembly, [scriptType, customEditorType]]
protected static Dictionary<Assembly, Dictionary<System.Type, System.Type>> ms_editorReferenceScript
= new Dictionary<Assembly, Dictionary<System.Type, System.Type>>();
protected List<Editor> m_inheritEditors = null; // cached editors
// ctor, use ctor instead Mono life circle, more user friendly
public InspectorDecoratorEditor()
{
CacheEditorReferenceScript();
}
#region Main Funcs
/// <summary>
/// Cache all CustomEditor in current Assembly
/// </summary>
protected void CacheEditorReferenceScript()
{
var editorAssembly = Assembly.GetAssembly(this.GetType()); // editor may in diferent assemblies
if(ms_editorReferenceScript.ContainsKey(editorAssembly) == false)
{
Dictionary<System.Type, System.Type> cachedData = new Dictionary<System.Type, System.Type>();
var types = editorAssembly.GetExportedTypes();
foreach(var editorType in types)
{
if(editorType.IsSubclassOf(BaseEditorType))
{
var scriptType = GetTypeFormCustomEditor(editorType);
if(scriptType != null)
{
cachedData[scriptType] = editorType;
}
}
}
ms_editorReferenceScript[editorAssembly] = cachedData;
}
}
/// <summary>
/// Draw a Target Type Inspector, call OnInspectorGUI
/// </summary>
/// <typeparam name="T"></typeparam>
protected virtual void DrawBaseInspectorGUI<T>() where T : InspectorDecoratorEditor
{
if(m_inheritEditors == null)
{
m_inheritEditors = new List<Editor>();
Dictionary<System.Type, System.Type> scriptEditorCache = null;
if(ms_editorReferenceScript.TryGetValue(Assembly.GetAssembly(this.GetType()), out scriptEditorCache) && scriptEditorCache != null)
{
var baseType = target.GetType().BaseType;
while(baseType != null && baseType != EndType)
{
System.Type editorType = null;
if(scriptEditorCache.TryGetValue(baseType, out editorType) && editorType != null)
{
m_inheritEditors.Add(Editor.CreateEditor(targets, editorType));
}
baseType = baseType.BaseType;
}
}
}
if(m_inheritEditors.Count > 0)
{
for(int i = m_inheritEditors.Count - 1; i >= 0; i--)
{
var drawTarget = m_inheritEditors[i];
if(drawTarget && drawTarget.GetType() == typeof(T))
{
drawTarget.OnInspectorGUI(); // draw target type only, avoid endless loop
break;
}
}
}
}
#endregion
#region Help Funcs
public static System.Type GetTypeFormCustomEditor(System.Type editorType)
{
var attributes = editorType.GetCustomAttributes(typeof(CustomEditor), false) as CustomEditor[];
if(attributes != null && attributes.Length > 0)
{
var attribute = attributes[0];
var type = attribute.GetType().GetField("m_InspectedType", CustomEditorFieldFlags).GetValue(attribute) as System.Type;
return type;
}
return null;
}
#endregion
}