Zinnia.Unity icon indicating copy to clipboard operation
Zinnia.Unity copied to clipboard

Add search options to AnyComponentTypeRule

Open bddckr opened this issue 7 years ago • 0 comments

AnyComponentTypeRule should allow setting what to search through when trying to find a component of a type.

If an enum flags type is used the implementation seems to need to be done manually completely as Unity's GetComponentInChildren has an overload that allows specifying whether to search inactive game objects, but the one taking a Type argument doesn't. On top of that GetComponentInParent doesn't have any overload taking that argument... Any implementation therefore needs to properly test combinations of search options, too, to really ensure these work.

Expand to see AnyComponentTypeRule.cs before it was simplified.

namespace VRTK.Core.Rule
{
    using UnityEngine;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using VRTK.Core.Data.Attribute;
    using VRTK.Core.Data.Type;
    using VRTK.Core.Extension;

    /// <summary>
    /// Determines whether a <see cref="GameObject"/> has any component found in a list.
    /// </summary>
    public class AnyComponentTypeRule : BaseGameObjectRule
    {
        /// <summary>
        /// Specifies how to search for <see cref="Component"/>s on a <see cref="GameObject"/>.
        /// </summary>
        [Flags]
        public enum SearchOptions
        {
            /// <summary>
            /// Search through the <see cref="GameObject"/>'s components.
            /// </summary>
            GameObjectItself = 1 << 0,
            /// <summary>
            /// Search upwards through the <see cref="GameObject"/> hierarchy's components.
            /// </summary>
            AnyParent = 1 << 1,
            /// <summary>
            /// Search downwards through the <see cref="GameObject"/> hierarchy's components.
            /// </summary>
            AnyChild = 1 << 2,
            /// <summary>
            /// Search through components of inactive <see cref="GameObject"/>s.
            /// </summary>
            IncludeInactiveGameObjects = 1 << 3
        }

        /// <summary>
        /// The component types to look for.
        /// </summary>
        [TypePicker(typeof(Component))]
        [Tooltip("The component types to look for.")]
        public List<SerializedType> componentTypes = new List<SerializedType>();
        /// <summary>
        /// The <see cref="SearchOptions"/> to use.
        /// </summary>
        [UnityFlags]
        [Tooltip("The SearchOptions to use.")]
        public SearchOptions searchOptions = SearchOptions.GameObjectItself | SearchOptions.IncludeInactiveGameObjects;

        /// <inheritdoc/>
        protected override bool Accepts(GameObject targetGameObject)
        {
            return componentTypes.EmptyIfNull()
                .Where(serializedType => serializedType.ActualType != null)
                .Any(
                    serializedType =>
                    {
                        bool includeInactiveGameObjects = searchOptions.HasFlag(SearchOptions.IncludeInactiveGameObjects);

                        bool result = false;
                        if (searchOptions.HasFlag(SearchOptions.GameObjectItself))
                        {
                            result = (includeInactiveGameObjects || !gameObject.activeInHierarchy)
                                && targetGameObject.GetComponent(serializedType) != null;
                        }

                        if (!result && searchOptions.HasFlag(SearchOptions.AnyParent))
                        {
                            Transform parent = targetGameObject.transform.parent;
                            while (!result && parent != null)
                            {
                                result = (includeInactiveGameObjects || !parent.gameObject.activeInHierarchy)
                                    && parent.GetComponent(serializedType) != null;
                            }
                        }

                        if (!result && searchOptions.HasFlag(SearchOptions.AnyChild))
                        {
                            Component component = targetGameObject.GetComponentInChildren(serializedType, includeInactiveGameObjects);
                            result = component != null && (includeInactiveGameObjects || component.gameObject != targetGameObject);
                        }

                        return result;
                    });
        }
    }
}

bddckr avatar Jul 15 '18 13:07 bddckr