Beispiel #1
0
        /// <summary>
        /// Searches the scene object hierarchy to find a child scene object using the provided path.
        /// </summary>
        /// <param name="root">Root scene object to which the path is relative to.</param>
        /// <param name="path">Path to the property, where each element of the path is separated with "/".
        ///
        ///                    Path elements signify names of child scene objects (first one relative to
        ///                    <paramref name="root"/>. Name of the root element should not be included in the path.
        ///                    Elements must be prefixed with "!" in order to match the path format of
        ///                    <see cref="FindProperty"/>.</param>
        /// <returns>Child scene object if found, or null otherwise.</returns>
        internal static SceneObject FindSceneObject(SceneObject root, string path)
        {
            if (string.IsNullOrEmpty(path) || root == null)
            {
                return(null);
            }

            string trimmedPath = path.Trim('/');

            string[] entries = trimmedPath.Split('/');

            // Find scene object referenced by the path
            SceneObject so      = root;
            int         pathIdx = 0;

            for (; pathIdx < entries.Length; pathIdx++)
            {
                string entry = entries[pathIdx];

                if (string.IsNullOrEmpty(entry))
                {
                    continue;
                }

                // Not a scene object, break
                if (entry[0] != '!')
                {
                    break;
                }

                string childName = entry.Substring(1, entry.Length - 1);
                so = so.FindChild(childName);

                if (so == null)
                {
                    break;
                }
            }

            return(so);
        }
Beispiel #2
0
        /// <summary>
        /// Searches the scene object hierarchy to find a property at the given path.
        /// </summary>
        /// <param name="root">Root scene object to which the path is relative to.</param>
        /// <param name="path">Path to the property, where each element of the path is separated with "/".
        ///
        ///                    Path elements prefixed with "!" signify names of child scene objects (first one relative to
        ///                    <paramref name="root"/>. Name of the root element should not be included in the path.
        ///
        ///                    Path element prefixed with ":" signify names of components. If a path doesn't have a
        ///                    component element, it is assumed the field is relative to the scene object itself (only
        ///                    "Position", "Rotation" and "Scale" fields are supported in such case). Only one component
        ///                    path element per path is allowed.
        ///
        ///                    Path entries with no prefix are considered regular script object fields. Each path must have
        ///                    at least one such entry.
        ///
        ///                    A field path can be followed by an indexer [n] where n is a zero-based index. Such paths
        ///                    are assumed to be referencing an index within an array or a list.
        ///
        ///                    A field path can also be followed by a suffix (after the indexer, if any) separated from the
        ///                    path name with ".". This suffix is not parsed internally, but will be returned as
        ///                    <paramref name="suffix"/>.
        ///
        ///                    Path examples:
        ///                     :MyComponent/myInt (path to myInt variable on a component attached to the root object)
        ///                     :MyComponent/myArray[0] (path to first element of myArray on the same component as above)
        ///                     !childSO/:MyComponent/myInt (path to myInt variable on a child scene object)
        ///                     !childSO/Position (path to the scene object position)
        ///                     :MyComponent/myVector.z (path to the z component of myVector on the root object)
        /// </param>
        /// <param name="suffix">Suffix of the last field entry, if it has any. Contains the suffix separator ".".</param>
        /// <returns>If found, property object you can use for setting and getting the value from the property, otherwise
        ///          null.</returns>
        internal static SerializableProperty FindProperty(SceneObject root, string path, out string suffix)
        {
            suffix = null;

            if (string.IsNullOrEmpty(path) || root == null)
            {
                return(null);
            }

            string trimmedPath = path.Trim('/');

            string[] entries = trimmedPath.Split('/');

            // Find scene object referenced by the path
            SceneObject so      = root;
            int         pathIdx = 0;

            for (; pathIdx < entries.Length; pathIdx++)
            {
                string entry = entries[pathIdx];

                if (string.IsNullOrEmpty(entry))
                {
                    continue;
                }

                // Not a scene object, break
                if (entry[0] != '!')
                {
                    break;
                }

                string childName = entry.Substring(1, entry.Length - 1);
                so = so.FindChild(childName);

                if (so == null)
                {
                    break;
                }
            }

            // Child scene object couldn't be found
            if (so == null)
            {
                return(null);
            }

            // Path too short, no field entry
            if (pathIdx >= entries.Length)
            {
                return(null);
            }

            // Check if path is referencing a component, and if so find it
            Component component = null;

            {
                string entry = entries[pathIdx];
                if (entry[0] == ':')
                {
                    string componentName = entry.Substring(1, entry.Length - 1);

                    Component[] components = so.GetComponents();
                    component = Array.Find(components, x => x.GetType().Name == componentName);

                    // Cannot find component with specified type
                    if (component == null)
                    {
                        return(null);
                    }
                }
            }

            // Look for a field within a component
            if (component != null)
            {
                pathIdx++;
                if (pathIdx >= entries.Length)
                {
                    return(null);
                }

                SerializableObject componentObj = new SerializableObject(component);

                StringBuilder pathBuilder = new StringBuilder();
                for (; pathIdx < entries.Length - 1; pathIdx++)
                {
                    pathBuilder.Append(entries[pathIdx] + "/");
                }

                // Check last path entry for suffix and remove it
                int suffixIdx = entries[pathIdx].LastIndexOf(".");
                if (suffixIdx != -1)
                {
                    string entryNoSuffix = entries[pathIdx].Substring(0, suffixIdx);
                    suffix = entries[pathIdx].Substring(suffixIdx, entries[pathIdx].Length - suffixIdx);

                    pathBuilder.Append(entryNoSuffix);
                }
                else
                {
                    pathBuilder.Append(entries[pathIdx]);
                }

                return(componentObj.FindProperty(pathBuilder.ToString()));
            }
            else // Field is one of the builtin ones on the SceneObject itself
            {
                if ((pathIdx + 1) < entries.Length)
                {
                    return(null);
                }

                string entry = entries[pathIdx];
                if (entry == "Position")
                {
                    SerializableProperty property = new SerializableProperty(
                        SerializableProperty.FieldType.Vector3,
                        typeof(Vector3),
                        () => so.LocalPosition,
                        (x) => so.LocalPosition = (Vector3)x);

                    return(property);
                }
                else if (entry == "Rotation")
                {
                    SerializableProperty property = new SerializableProperty(
                        SerializableProperty.FieldType.Vector3,
                        typeof(Vector3),
                        () => so.LocalRotation.ToEuler(),
                        (x) => so.LocalRotation = Quaternion.FromEuler((Vector3)x));

                    return(property);
                }
                else if (entry == "Scale")
                {
                    SerializableProperty property = new SerializableProperty(
                        SerializableProperty.FieldType.Vector3,
                        typeof(Vector3),
                        () => so.LocalScale,
                        (x) => so.LocalScale = (Vector3)x);

                    return(property);
                }

                return(null);
            }
        }