public bool Process(ref TypeSearchInfo info, ref string errorMessage)
 {
     return(this.rule(ref info, ref errorMessage));
 }
Beispiel #2
0
        static DrawerUtilities()
        {
            // This method is *very* expensive performance-wise and generates lots of garbage due to liberal use of LINQ for readability.
            // This is acceptable, as it only runs once per AppDomain reload, and only ever in the editor.

            //
            // First, get all relevant types
            //

            var typesToSearch = AssemblyUtilities.GetTypes(AssemblyTypeFlags.CustomTypes | AssemblyTypeFlags.UnityEditorTypes)
                                .Where(type => !type.IsAbstract && type.IsClass && !type.IsDefined(typeof(OdinDontRegisterAttribute), false) && (typeof(OdinDrawer).IsAssignableFrom(type) || (typeof(GUIDrawer).IsAssignableFrom(type) && (!(type.Namespace ?? "").StartsWith("Unity", StringComparison.InvariantCulture) || !ExcludeUnityDrawers.Contains(type.Name)))))
                                .ToArray();

            //
            // Find all regular Unity property and decorator drawers and create alias drawers for them
            //

            IEnumerable <Type> unityPropertyDrawers;
            IEnumerable <Type> unityPropertyAttributeDrawers;
            IEnumerable <Type> unityDecoratorDrawers;

            if (DrawerUtilities.CustomPropertyDrawerTypeField != null && DrawerUtilities.CustomPropertyDrawerUseForChildrenField != null)
            {
                unityPropertyDrawers =
                    typesToSearch.Where(type => type.IsGenericTypeDefinition == false && typeof(PropertyDrawer).IsAssignableFrom(type) && type.GetConstructor(Type.EmptyTypes) != null)
                    .SelectMany(type => type.GetCustomAttributes <CustomPropertyDrawer>(true).Select(attr => new { Type = type, Attribute = attr }))
                    .Where(n =>
                {
                    if (n.Attribute != null)
                    {
                        var drawnType = CustomPropertyDrawerTypeField.GetValue(n.Attribute) as Type;

                        if (drawnType != null && !typeof(PropertyAttribute).IsAssignableFrom(drawnType))
                        {
                            return(true);
                        }
                    }

                    return(false);
                })
                    .Select(n =>
                {
                    var drawnType = (Type)CustomPropertyDrawerTypeField.GetValue(n.Attribute);

                    if (drawnType.IsAbstract || (bool)DrawerUtilities.CustomPropertyDrawerUseForChildrenField.GetValue(n.Attribute))
                    {
                        var tArg = typeof(AbstractTypeUnityPropertyDrawer <, ,>).GetGenericArguments()[2];
                        return(typeof(AbstractTypeUnityPropertyDrawer <, ,>).MakeGenericType(n.Type, drawnType, tArg));
                    }
                    else
                    {
                        return(typeof(UnityPropertyDrawer <,>).MakeGenericType(n.Type, drawnType));
                    }
                });

                unityPropertyAttributeDrawers =
                    typesToSearch.Where(type => type.IsGenericTypeDefinition == false && typeof(PropertyDrawer).IsAssignableFrom(type) && type.GetConstructor(Type.EmptyTypes) != null)
                    .SelectMany(type => type.GetCustomAttributes <CustomPropertyDrawer>(true).Select(attr => new { Type = type, Attribute = attr }))
                    .Where(n =>
                {
                    if (n.Attribute != null)
                    {
                        var drawnType = CustomPropertyDrawerTypeField.GetValue(n.Attribute) as Type;

                        if (drawnType != null && typeof(PropertyAttribute).IsAssignableFrom(drawnType))
                        {
                            return(true);
                        }
                    }

                    return(false);
                })
                    .Select(n =>
                {
                    Type drawnType = (Type)CustomPropertyDrawerTypeField.GetValue(n.Attribute);

                    if ((bool)DrawerUtilities.CustomPropertyDrawerUseForChildrenField.GetValue(n.Attribute))
                    {
                        var tAttributeArgParam = typeof(UnityPropertyAttributeDrawer <, ,>).GetGenericArguments()[1];
                        return(typeof(UnityPropertyAttributeDrawer <, ,>).MakeGenericType(n.Type, tAttributeArgParam, drawnType));
                    }
                    else
                    {
                        return(typeof(UnityPropertyAttributeDrawer <, ,>).MakeGenericType(n.Type, drawnType, typeof(PropertyAttribute)));
                    }
                });

                unityDecoratorDrawers =
                    typesToSearch.Where(type => type.IsGenericTypeDefinition == false && typeof(DecoratorDrawer).IsAssignableFrom(type) && type.GetConstructor(Type.EmptyTypes) != null)
                    .Select(type => new { Type = type, Attribute = type.GetCustomAttribute <CustomPropertyDrawer>(true) })
                    .Where(n => n.Attribute != null)
                    .Select(n => new { Type = n.Type, Attribute = n.Attribute, DrawnType = CustomPropertyDrawerTypeField.GetValue(n.Attribute) as Type })
                    .Where(n => n.DrawnType != null && typeof(PropertyAttribute).IsAssignableFrom(n.DrawnType))
                    .Select(n =>
                {
                    if ((bool)DrawerUtilities.CustomPropertyDrawerUseForChildrenField.GetValue(n.Attribute))
                    {
                        var tAttributeArgParam = typeof(UnityDecoratorAttributeDrawer <, ,>).GetGenericArguments()[1];
                        return(typeof(UnityDecoratorAttributeDrawer <, ,>).MakeGenericType(n.Type, tAttributeArgParam, n.DrawnType));
                    }
                    else
                    {
                        return(typeof(UnityDecoratorAttributeDrawer <, ,>).MakeGenericType(n.Type, n.DrawnType, typeof(PropertyAttribute)));
                    }
                });
            }
            else
            {
                Debug.LogWarning("Could not find internal fields 'm_Type' and/or 'm_UseForChildren' in type CustomPropertyDrawer in this version of Unity; support for legacy Unity PropertyDrawers and DecoratorDrawers have been disabled in Odin's inspector. Please report this on Odin's issue tracker.");
                unityPropertyDrawers          = Enumerable.Empty <Type>();
                unityPropertyAttributeDrawers = Enumerable.Empty <Type>();
                unityDecoratorDrawers         = Enumerable.Empty <Type>();
            }

            DrawerUtilities.AllDrawerTypes = typesToSearch
                                             .Where(type => typeof(OdinDrawer).IsAssignableFrom(type))
                                             .AppendWith(unityPropertyDrawers)
                                             .AppendWith(unityPropertyAttributeDrawers)
                                             .AppendWith(unityDecoratorDrawers)
                                             .OrderByDescending(type => GetDrawerPriority(type))
                                             .ToList();

            //DrawerUtilities.SearchIndex.IndexingRules.Add(new TypeMatchIndexingRule(
            //    "DEBUG",
            //    (ref TypeSearchInfo info, ref string error) =>
            //    {
            //        Debug.Log("Indexed drawer: " + info.MatchType.GetNiceFullName());
            //        return true;
            //    }));

            // Unity drawers have a peculiar method of generic target selection,
            // where you pass in the generic type definition that you wish to draw.
            //
            // We need to support this, for Unity's own legacy drawers.
            DrawerUtilities.SearchIndex.MatchRules.Add(new TypeSearch.TypeMatchRule(
                                                           "Unity Drawer Generic Target Matcher",
                                                           (info, targets) =>
            {
                if (targets.Length != 1)
                {
                    return(null);
                }
                if (!info.Targets[0].IsGenericTypeDefinition)
                {
                    return(null);
                }

                var baseDef = info.MatchType.GetGenericTypeDefinition();

                bool abstractUnityValueDrawer = baseDef == typeof(AbstractTypeUnityPropertyDrawer <, ,>);
                bool plainUnityValueDrawer    = baseDef == typeof(UnityPropertyDrawer <,>);

                if (!(abstractUnityValueDrawer || plainUnityValueDrawer))
                {
                    return(null);
                }

                if (abstractUnityValueDrawer)
                {
                    if (targets[0].ImplementsOpenGenericType(info.Targets[0]))
                    {
                        var args = info.MatchType.GetGenericArguments();
                        return(info.MatchType.GetGenericTypeDefinition().MakeGenericType(args[0], targets[0], targets[0]));
                    }
                }
                else
                {
                    if (!targets[0].IsGenericType)
                    {
                        return(null);
                    }

                    if (targets[0].GetGenericTypeDefinition() == info.Targets[0])
                    {
                        var args = info.MatchType.GetGenericArguments();
                        return(info.MatchType.GetGenericTypeDefinition().MakeGenericType(args[0], targets[0]));
                    }
                }

                return(null);
            })
                                                       );

            DrawerUtilities.SearchIndex.AddIndexedTypes(
                DrawerUtilities.AllDrawerTypes
                .Select((type, i) =>
            {
                var info = new TypeSearchInfo()
                {
                    MatchType = type,
                    Priority  = DrawerUtilities.AllDrawerTypes.Count - i,
                    Targets   = null
                };

                if (type.ImplementsOpenGenericClass(typeof(OdinValueDrawer <>)))
                {
                    info.Targets = type.GetArgumentsOfInheritedOpenGenericClass(typeof(OdinValueDrawer <>));
                }
                else if (type.ImplementsOpenGenericClass(typeof(OdinAttributeDrawer <>)))
                {
                    if (type.ImplementsOpenGenericClass(typeof(OdinAttributeDrawer <,>)))
                    {
                        info.Targets = type.GetArgumentsOfInheritedOpenGenericClass(typeof(OdinAttributeDrawer <,>));
                        InvalidAttributeTargetUtility.RegisterValidAttributeTarget(info.Targets[0], info.Targets[1]);
                    }
                    else
                    {
                        info.Targets = type.GetArgumentsOfInheritedOpenGenericClass(typeof(OdinAttributeDrawer <>));
                    }
                }
                else if (type.ImplementsOpenGenericClass(typeof(OdinGroupDrawer <>)))
                {
                    info.Targets = type.GetArgumentsOfInheritedOpenGenericClass(typeof(OdinGroupDrawer <>));
                }
                else if (!type.IsFullyConstructedGenericType())
                {
                    info.Targets = type.GetGenericArguments();
                }

                info.Targets = info.Targets ?? Type.EmptyTypes;
                return(info);
            })
                );
        }