Пример #1
0
        /// <summary>
        /// Returns all instances matching pathName
        /// </summary>
        /// <param name="pathName">is interpreted as either a path or a name</param>
        /// <returns></returns>
        /// <remarks>
        /// Counterpart to GameObject.Find(string) this returns all matching instances, instead of one.
        /// Names beginning with '/' indicate objects at the root of the scene.
        /// Names including '/' will be traversed as a path beginning from the first matched object.
        /// </remarks>
        public static GameObject[] FindAll(string pathName)
        {
            // PROBLEM: Actually, empty names are allowed...
            // Empty object names are not allowed
            if (pathName.Length == 0)
            {
                return(new GameObject[0]);
            }

            // This behavior is consistent with GameObject.Find()
            if (pathName[0] != '/')
            {
                return(NameFind(pathName));
            }

            // Search by path
            // IMPORTANT: PathName names begin with the name of a GameObject, so "/" is dropped
            var path = new PathName(pathName.Substring(1), PathName.PathStep.Step.Path);

            var transformList  = path.Find();
            var gameObjectList = new List <GameObject>();

            foreach (var transform in transformList)
            {
                gameObjectList.Add(transform.gameObject);
            }
            return(gameObjectList.ToArray());
        }
Пример #2
0
        // TODO: Find should identify unique instance
        // TODO: Check if path is unique for object (with optional root)
        // TODO: Implement forcing of unique name for GameObject
        // - Rename GameObject
        // - Rename all identically named siblings

        // TODO: This should return GameObjects

        /// <returns>the GameObjects specified by this path relative to parent</returns>
        /// <remarks>
        /// If the path matches no GameObjects the returned array will be empty.
        /// An empty path matches parent.
        /// A null parent matches active scene.
        /// </remarks>
        public Transform[] Find(Transform parent = null)
        {
            if (path.Count == 0)
            {
                return new Transform[] { parent }
            }
            ;

            List <Transform> findList = new List <Transform>();

            Transform[] childList = TransformExtensions.Children(parent);
            foreach (var childItem in childList)
            {
                // Evaluate match
                var lhsRecurse = Clone() as PathName;

                var rhsRecurse = new PathName(childItem.name, PathStep.Step.Name);
                if (!MatchStep(lhsRecurse, rhsRecurse))
                {
                    continue;
                }
                findList.AddRange(lhsRecurse.Find(childItem));
            }
            return(findList.ToArray());
        }
Пример #3
0
            public EditGameObject(GameObject gameObject)
            {
                if (useEditorAction)
                {
#if UNITY_EDITOR
                    editObjectType = GetGameObjectType(gameObject);
                    switch (editObjectType)
                    {
                    case GameObjectType.Persistent: {
                        // Load as PreviewScene Object
                        editAssetPath = AssetDatabase.GetAssetPath(gameObject);
                        editPrefab    = PrefabUtility.LoadPrefabContents(editAssetPath);
                        editObject    = editPrefab;
                        break;
                    }

                    case GameObjectType.Connected: {
                        // Path to gameObject relative to prefab
                        // NOTE: EditorSceneManager.IsPreviewSceneObject(editPrefab) == true
                        var prefab = PrefabUtility.GetNearestPrefabInstanceRoot(gameObject);
                        var path   = new PathName(gameObject, prefab);

                        // Instantiate a copy of prefab and locate copy of gameObject
                        var asset = PrefabUtility.GetCorrespondingObjectFromSource(prefab);
                        editAssetPath = AssetDatabase.GetAssetPath(asset);
                        editPrefab    = PrefabUtility.InstantiatePrefab(asset) as GameObject;
                        var editObjectList = path.Find(editPrefab.transform);
                        if (editObjectList.Length == 1)
                        {
                            editObject = editObjectList[0].gameObject;
                        }
                        break;
                    }

                    case GameObjectType.Instance:
                        editObject = gameObject;
                        break;
                    }

                    if (Application.isBatchMode)
                    {
                        EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
                    }
                    else
                    {
                        // QUESTION: Does this work for prefabs?
                        Undo.RecordObject(gameObject, $"Edit {gameObject.name}");
                    }
#endif
                }
                else
                {
                    editObject = gameObject;
                }
            }
Пример #4
0
        /// <returns>an array of all GameObjects identified by path from parent</returns>
        /// <remarks>
        /// When parent = null the search begins with the scene root.
        /// </remarks>
        public static GameObject[] PathFind(PathName path, Transform parent = null)
        {
            var transformList  = path.Find(parent);
            var gameObjectList = new List <GameObject>();

            foreach (var transform in transformList)
            {
                gameObjectList.Add(transform.gameObject);
            }
            return(gameObjectList.ToArray());
        }
Пример #5
0
        /// <returns>deep-copy yielding an independent instance of path</returns>
        public object Clone()
        {
            var pathName = new PathName();

            pathName.path = new List <PathStep>();
            foreach (var step in path)
            {
                pathName.path.Add(step.Clone() as PathStep);
            }
            return(pathName);
        }
Пример #6
0
        public static void ApplyTo(GameObject gameObject)
        {
            using (var editScope = new EP.EditGameObject(gameObject)) {
                var editObject = editScope.editObject;
                // Gather all MeshRenderer components that are leaf nodes
                // NOTE: Prefab components will be managed by applying AutoLOD to the prefab
                var children = editObject.Children(true);
                var groups   = new Dictionary <PathName, List <GameObject> >();
                foreach (var child in children)
                {
                    // Only gather leaf node renderers
                    if (child.transform.childCount > 0)
                    {
                        continue;
                    }
                    // AutoLOD will be applied to child prefabs separately
                    var childPrefab = PrefabUtility.GetNearestPrefabInstanceRoot(child);
                    if (childPrefab != null && childPrefab != editObject)
                    {
                        continue;
                    }
                    var hasRenderer = child.GetComponent <Renderer>();
                    if (!hasRenderer)
                    {
                        continue;
                    }
                    // MeshRenderers will be managed by LODGroup
                    var inGroup = child.GetComponentInParent <LODGroup>();
                    if (inGroup)
                    {
                        continue;
                    }
                    // Add renderer to group
                    var path = new PathName(child);
                    if (!groups.ContainsKey(path))
                    {
                        groups.Add(path, new List <GameObject>());
                    }
                    groups[path].Add(child);
                }

                // Combine group renderers under LODGroup managers
                foreach (var pathGroup in groups)
                {
                    MergeGroup(pathGroup.Key, pathGroup.Value);
                }
            }
        }
Пример #7
0
        /// <returns>an array of all GameObject matching name that are children of parent</returns>
        /// <remarks>
        /// Unlike Transform.Find() path separators are assumed to be a part of the name.
        /// When parent = null the search begins with the scene root.
        /// </remarks>
        public static GameObject[] NameFind(PathName name, Transform parent = null, bool recurse = false)
        {
            List <GameObject> findList = new List <GameObject>();

            Transform[] childList = TransformExtensions.Children(parent);
            foreach (var child in childList)
            {
                if (name == child.name)
                {
                    findList.Add(child.gameObject);
                }
                if (recurse)
                {
                    findList.AddRange(NameFind(name, child, recurse));
                }
            }
            return(findList.ToArray());
        }
Пример #8
0
        // WARNING: If there is a name override, PathName will not resolve!

        // TODO: Find a way to clone prefab with overrides intact.
        // QUESTION: Is there a way to accomplish instatiation using object serializations?
        // Ideally, this would handle the connection and override persistence.
        // https://docs.unity3d.com/ScriptReference/SerializedObject.html
        // Construct, then iterate & copy?

        static GameObject InstantiateChild(GameObject original, GameObject parent)
        {
            GameObject child = null;
            // IMPORTANT: PrefabUtility.InstantiatePrefab applies only to assets, not to instances
            // IMPORTANT: PrefabUtility.GetCorrespondingObjectFromSource applies only to instances, not to assets
            var        asset      = PrefabUtility.GetCorrespondingObjectFromSource(parent);
            GameObject copy_asset = null;

            if (asset)
            {
                copy_asset = asset;
            }
            else
            {
                copy_asset = original;
            }
            var copy = PrefabUtility.InstantiatePrefab(copy_asset) as GameObject;

            if (parent != original)
            {
                var path = new PathName(original, parent);
                var find = path.Find(copy.transform);
                if (find.Length == 1)
                {
                    child = find[0].gameObject;
                    // Unpack to enable orphaning, only once since nearest root was instantiated
                    var unpack = PrefabUtility.GetOutermostPrefabInstanceRoot(child);
                    while (unpack)
                    {
                        PrefabUtility.UnpackPrefabInstance(unpack, PrefabUnpackMode.OutermostRoot, InteractionMode.AutomatedAction);
                        unpack = PrefabUtility.GetOutermostPrefabInstanceRoot(child);
                    }
                    child.transform.SetParent(null);
                }
                EP.Destroy(copy);
            }
            else
            {
                child = copy;
            }
            return(child);
        }
Пример #9
0
 /// <returns>an array of all GameObjects identified by path from this</returns>
 public static GameObject[] PathFindInChildren(this GameObject gameObject, PathName pathName)
 {
     return(PathFind(pathName, gameObject?.transform));
 }
Пример #10
0
 /// <returns>an array of all GameObjects identified by path from this</returns>
 public static GameObject[] PathFindInChildren(this Component component, PathName pathName)
 {
     return(PathFind(pathName, component?.transform));
 }
Пример #11
0
 /// <returns>an array of all child GameObjects matching name</returns>
 public static GameObject[] NameFindInChildren(this GameObject gameObject, PathName name, bool recurse = false)
 {
     return(NameFind(name, gameObject?.transform, recurse));
 }
Пример #12
0
        /// <summary>
        /// Evaluates a single step of a match.
        /// </summary>
        /// <returns>false when incompatibility is found</returns>
        /// <remarks>
        /// In the case of a match, arguments will be modified according
        /// to their respective recursion types.
        /// </remarks>
        public static bool MatchStep(PathName lhs, PathName rhs)
        {
            // Empty path denotes root, so empty paths are equal
            if (lhs.path.Count == 0 && rhs.path.Count == 0)
            {
                return(true);
            }
            if (lhs.path.Count == 0 || rhs.path.Count == 0)
            {
                return(false);
            }

            // Count the matching characters from start of path step name
            int same = 0;

            for (int c = 0; c < lhs.path[0].name.Length && c < rhs.path[0].name.Length; ++c)
            {
                if (lhs.path[0].name[c] != rhs.path[0].name[c])
                {
                    break;
                }
                ++same;
            }

            switch (lhs.path[0].step)
            {
            case PathStep.Step.Name:
                if (same < lhs.path[0].name.Length)
                {
                    return(false);
                }
                lhs.path.RemoveAt(0);                 // Recurse by reduction
                break;

            case PathStep.Step.Path:
                if (same < lhs.path[0].name.Length)
                {
                    if (lhs.path[0].name[same] != '/')
                    {
                        return(false);
                    }
                    lhs.path[0].name = lhs.path[0].name.Substring(same + 1);                     // Recurse by partition
                    break;
                }
                lhs.path.RemoveAt(0);                 // Recurse by reduction
                break;
            }
            switch (rhs.path[0].step)
            {
            case PathStep.Step.Name:
                if (same < rhs.path[0].name.Length)
                {
                    return(false);
                }
                rhs.path.RemoveAt(0);                 // Recurse by reduction
                break;

            case PathStep.Step.Path:
                if (same < rhs.path[0].name.Length)
                {
                    if (rhs.path[0].name[same] != '/')
                    {
                        return(false);
                    }
                    rhs.path[0].name = rhs.path[0].name.Substring(same + 1);                     // Recurse by partition
                    break;
                }
                rhs.path.RemoveAt(0);                 // Recurse by reduction
                break;
            }

            return(true);
        }