summaryrefslogtreecommitdiff
path: root/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Utilities/ObjectReferenceField.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Library/PackageCache/com.unity.timeline@1.2.13/Editor/Utilities/ObjectReferenceField.cs')
-rw-r--r--Library/PackageCache/com.unity.timeline@1.2.13/Editor/Utilities/ObjectReferenceField.cs195
1 files changed, 195 insertions, 0 deletions
diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Utilities/ObjectReferenceField.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Utilities/ObjectReferenceField.cs
new file mode 100644
index 0000000..3ace197
--- /dev/null
+++ b/Library/PackageCache/com.unity.timeline@1.2.13/Editor/Utilities/ObjectReferenceField.cs
@@ -0,0 +1,195 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using UnityEngine;
+using UnityEngine.Timeline;
+using UnityEditor;
+using UnityEditor.SceneManagement;
+using UnityEngine.Playables;
+using Object = UnityEngine.Object;
+
+namespace UnityEditor.Timeline
+{
+ // Describes the object references on a ScriptableObject, ignoring script fields
+ struct ObjectReferenceField
+ {
+ public string propertyPath;
+ public bool isSceneReference;
+ public System.Type type;
+
+ private readonly static ObjectReferenceField[] None = new ObjectReferenceField[0];
+ private readonly static Dictionary<System.Type, ObjectReferenceField[]> s_Cache = new Dictionary<System.Type, ObjectReferenceField[]>();
+
+ public static ObjectReferenceField[] FindObjectReferences(System.Type type)
+ {
+ if (type == null)
+ return None;
+
+ if (type.IsAbstract || type.IsInterface)
+ return None;
+
+ if (!typeof(ScriptableObject).IsAssignableFrom(type))
+ return None;
+
+ ObjectReferenceField[] result = null;
+ if (s_Cache.TryGetValue(type, out result))
+ return result;
+
+ result = SearchForFields(type);
+ s_Cache[type] = result;
+ return result;
+ }
+
+ public static ObjectReferenceField[] FindObjectReferences<T>() where T : ScriptableObject, new()
+ {
+ return FindObjectReferences(typeof(T));
+ }
+
+ private static ObjectReferenceField[] SearchForFields(System.Type t)
+ {
+ Object instance = ScriptableObject.CreateInstance(t);
+ var list = new List<ObjectReferenceField>();
+
+ var serializableObject = new SerializedObject(instance);
+ var prop = serializableObject.GetIterator();
+ bool enterChildren = true;
+ while (prop.NextVisible(enterChildren))
+ {
+ enterChildren = true;
+ var ppath = prop.propertyPath;
+ if (ppath == "m_Script")
+ {
+ enterChildren = false;
+ }
+ else if (prop.propertyType == SerializedPropertyType.ObjectReference || prop.propertyType == SerializedPropertyType.ExposedReference)
+ {
+ enterChildren = false;
+ var exposedType = GetTypeFromPath(t, prop.propertyPath);
+ if (exposedType != null && typeof(Object).IsAssignableFrom(exposedType))
+ {
+ bool isSceneRef = prop.propertyType == SerializedPropertyType.ExposedReference;
+ list.Add(
+ new ObjectReferenceField() {propertyPath = prop.propertyPath, isSceneReference = isSceneRef, type = exposedType}
+ );
+ }
+ }
+ }
+
+ Object.DestroyImmediate(instance);
+ if (list.Count == 0)
+ return None;
+ return list.ToArray();
+ }
+
+ private static System.Type GetTypeFromPath(System.Type baseType, string path)
+ {
+ if (string.IsNullOrEmpty(path))
+ return null;
+
+ System.Type parentType = baseType;
+ FieldInfo field = null;
+ var pathTo = path.Split(new char[] {'.'}, StringSplitOptions.RemoveEmptyEntries);
+ var flags = BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.NonPublic |
+ BindingFlags.Instance;
+ foreach (string s in pathTo)
+ {
+ field = parentType.GetField(s, flags);
+ while (field == null)
+ {
+ if (parentType.BaseType == null)
+ return null; // Should not happen really. Means SerializedObject got the property, but the reflection missed it
+ parentType = parentType.BaseType;
+ field = parentType.GetField(s, flags);
+ }
+
+ parentType = field.FieldType;
+ }
+
+ // dig out exposed reference types
+ if (field.FieldType.IsGenericType && field.FieldType.GetGenericTypeDefinition() == typeof(ExposedReference<Object>).GetGenericTypeDefinition())
+ {
+ return field.FieldType.GetGenericArguments()[0];
+ }
+
+ return field.FieldType;
+ }
+
+ public Object Find(ScriptableObject sourceObject, Object context = null)
+ {
+ if (sourceObject == null)
+ return null;
+
+ SerializedObject obj = new SerializedObject(sourceObject, context);
+ var prop = obj.FindProperty(propertyPath);
+ if (prop == null)
+ throw new InvalidOperationException("sourceObject is not of the proper type. It does not contain a path to " + propertyPath);
+
+ Object result = null;
+ if (isSceneReference)
+ {
+ if (prop.propertyType != SerializedPropertyType.ExposedReference)
+ throw new InvalidOperationException(propertyPath + " is marked as a Scene Reference, but is not an exposed reference type");
+ if (context == null)
+ Debug.LogWarning("ObjectReferenceField.Find " + " is called on a scene reference without a context, will always be null");
+
+ result = prop.exposedReferenceValue;
+ }
+ else
+ {
+ if (prop.propertyType != SerializedPropertyType.ObjectReference)
+ throw new InvalidOperationException(propertyPath + "is marked as an asset reference, but is not an object reference type");
+ result = prop.objectReferenceValue;
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// Check if an Object satisfies this field, including components
+ /// </summary>
+ public bool IsAssignable(Object obj)
+ {
+ if (obj == null)
+ return false;
+
+ // types match
+ bool potentialMatch = type.IsAssignableFrom(obj.GetType());
+
+ // field is component, and it exists on the gameObject
+ if (!potentialMatch && typeof(Component).IsAssignableFrom(type) && obj is GameObject)
+ potentialMatch = ((GameObject)obj).GetComponent(type) != null;
+
+ return potentialMatch && isSceneReference == obj.IsSceneObject();
+ }
+
+ /// <summary>
+ /// Assigns a value to the field
+ /// </summary>
+ public bool Assign(ScriptableObject scriptableObject, Object value, IExposedPropertyTable exposedTable = null)
+ {
+ var serializedObject = new SerializedObject(scriptableObject, exposedTable as Object);
+ var property = serializedObject.FindProperty(propertyPath);
+ if (property == null)
+ return false;
+
+ // if the value is a game object, but the field is a component
+ if (value is GameObject && typeof(Component).IsAssignableFrom(type))
+ value = ((GameObject)value).GetComponent(type);
+
+ if (isSceneReference)
+ {
+ property.exposedReferenceValue = value;
+
+ // the object gets dirtied, but not the scene which is where the reference is stored
+ var component = exposedTable as Component;
+ if (component != null && !EditorApplication.isPlaying)
+ EditorSceneManager.MarkSceneDirty(component.gameObject.scene);
+ }
+ else
+ property.objectReferenceValue = value;
+
+ serializedObject.ApplyModifiedProperties();
+ return true;
+ }
+ }
+}