Beispiel #1
0
        /// <summary>
        /// Helper method used for finding child properties of the specified property, using a property path.
        /// <see cref="SerializableObject.FindProperty(string)"/>.
        /// </summary>
        /// <param name="pathElements">Path elements representing field names and keys to look for.</param>
        /// <param name="elementIdx">Index in the <paramref name="pathElements"/> array to start the search at.</param>
        /// <returns>Property representing the final path element, or null if not found (array index is out of range, or
        ///          property with that path doesn't exist).</returns>
        internal SerializableProperty FindProperty(PropertyPathElement[] pathElements, int elementIdx)
        {
            switch (type)
            {
            case FieldType.Object:
            {
                SerializableObject childObject = GetObject();

                return(childObject.FindProperty(pathElements, elementIdx));
            }

            case FieldType.Array:
            {
                SerializableArray childArray = GetArray();

                return(childArray.FindProperty(pathElements, elementIdx));
            }

            case FieldType.List:
            {
                SerializableList childList = GetList();

                return(childList.FindProperty(pathElements, elementIdx));
            }

            case FieldType.Dictionary:
            {
                SerializableDictionary childDictionary = GetDictionary();

                return(childDictionary.FindProperty(pathElements, elementIdx));
            }
            }

            return(null);
        }
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);
            }
        }