private static extern void Internal_CreateInstance(SerializableObject instance, Type objectType);
/// <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); } }