private static extern void Internal_CreateInstance(SerializableProperty instance, Type type);
/// <summary> /// Builds a list of properties that will be animated using float animation curves. /// </summary> /// <param name="clip">Clip to retrieve the float animation curves from.</param> partial void RebuildFloatProperties(RRef <AnimationClip> clip) { if (clip == null) { floatProperties = null; return; } AnimationCurves curves = clip.Value.Curves; List <FloatCurvePropertyInfo> newFloatProperties = new List <FloatCurvePropertyInfo>(); for (int i = 0; i < curves.Generic.Length; i++) { bool isMorphCurve = curves.Generic[i].flags.HasFlag(AnimationCurveFlags.MorphWeight) || curves.Generic[i].flags.HasFlag(AnimationCurveFlags.MorphFrame); if (isMorphCurve) { continue; } string suffix; SerializableProperty property = FindProperty(SceneObject, curves.Generic[i].name, out suffix); if (property == null) { continue; } int elementIdx = 0; if (!string.IsNullOrEmpty(suffix)) { PropertySuffixInfo suffixInfo; if (PropertySuffixInfos.TryGetValue(suffix, out suffixInfo)) { elementIdx = suffixInfo.elementIdx; } } Action <float> setter = null; Type internalType = property.InternalType; switch (property.Type) { case SerializableProperty.FieldType.Vector2: if (internalType == typeof(Vector2)) { setter = f => { Vector2 value = property.GetValue <Vector2>(); value[elementIdx] = f; property.SetValue(value); }; } break; case SerializableProperty.FieldType.Vector3: if (internalType == typeof(Vector3)) { setter = f => { Vector3 value = property.GetValue <Vector3>(); value[elementIdx] = f; property.SetValue(value); }; } break; case SerializableProperty.FieldType.Vector4: if (internalType == typeof(Vector4)) { setter = f => { Vector4 value = property.GetValue <Vector4>(); value[elementIdx] = f; property.SetValue(value); }; } else if (internalType == typeof(Quaternion)) { setter = f => { Quaternion value = property.GetValue <Quaternion>(); value[elementIdx] = f; property.SetValue(value); }; } break; case SerializableProperty.FieldType.Color: if (internalType == typeof(Color)) { setter = f => { Color value = property.GetValue <Color>(); value[elementIdx] = f; property.SetValue(value); }; } break; case SerializableProperty.FieldType.Bool: setter = f => { bool value = f > 0.0f; property.SetValue(value); }; break; case SerializableProperty.FieldType.Int: setter = f => { int value = (int)f; property.SetValue(value); }; break; case SerializableProperty.FieldType.Float: setter = f => { property.SetValue(f); }; break; } if (setter == null) { continue; } FloatCurvePropertyInfo propertyInfo = new FloatCurvePropertyInfo(); propertyInfo.curveIdx = i; propertyInfo.setter = setter; newFloatProperties.Add(propertyInfo); } floatProperties = newFloatProperties.ToArray(); }
/// <summary> /// Constructor for use by the runtime only. /// </summary> /// <param name="elementType">C# type of the elements in the array.</param> /// <param name="parentProperty">Property used for retrieving this entry.</param> private SerializableArray(Type elementType, SerializableProperty parentProperty) { this.parentProperty = parentProperty; this.elementType = elementType; elementPropertyType = SerializableProperty.DetermineFieldType(elementType); }
/// <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); } }
/// <summary> /// Uses the provided path elements to find an dictionary element with the specified key, and returns a property /// to the element, or to a child property of that element. /// </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 (key or property with that path /// doesn't exist).</returns> internal SerializableProperty FindProperty(PropertyPathElement[] pathElements, int elementIdx) { if (pathElements[elementIdx].key == null) { return(null); } object key = null; switch (KeyPropertyType) { case SerializableProperty.FieldType.String: key = pathElements[elementIdx].key; break; case SerializableProperty.FieldType.Bool: bool boolKey; if (bool.TryParse(pathElements[elementIdx].key, out boolKey)) { key = boolKey; } break; case SerializableProperty.FieldType.Int: int intKey; if (int.TryParse(pathElements[elementIdx].key, out intKey)) { key = intKey; } break; case SerializableProperty.FieldType.Float: float floatKey; if (float.TryParse(pathElements[elementIdx].key, out floatKey)) { key = floatKey; } break; } if (key == null) { return(null); } SerializableProperty property = GetProperty(key).Value; if (elementIdx == (pathElements.Length - 1)) { return(property); } if (property != null) { return(property.FindProperty(pathElements, elementIdx + 1)); } return(null); }