Modelowanie_Wirtualnych_Swi.../Library/PackageCache/com.unity.timeline@1.5.4/Editor/Utilities/TypeUtility.cs
2021-07-09 23:35:24 +02:00

343 lines
13 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
using Component = UnityEngine.Component;
using Object = UnityEngine.Object;
namespace UnityEditor.Timeline
{
static class TypeUtility
{
private static Type[] s_AllTrackTypes;
private static Type[] s_AllClipTypes;
private static Type[] s_MarkerTypes;
private static Dictionary<Type, Type[]> s_TrackTypeToVisibleClipType = new Dictionary<Type, Type[]>();
private static Dictionary<Type, Type[]> s_TrackTypeToAllClipType = new Dictionary<Type, Type[]>();
private static Dictionary<Type, TrackBindingTypeAttribute> s_TrackToBindingCache = new Dictionary<Type, TrackBindingTypeAttribute>();
public static bool IsConcretePlayableAsset(Type t)
{
return typeof(IPlayableAsset).IsAssignableFrom(t)
&& IsConcreteAsset(t);
}
private static bool IsConcreteAsset(Type t)
{
return typeof(ScriptableObject).IsAssignableFrom(t)
&& !t.IsAbstract
&& !t.IsGenericType
&& !t.IsInterface
&& !typeof(TrackAsset).IsAssignableFrom(t)
&& !typeof(TimelineAsset).IsAssignableFrom(t);
}
/// <summary>
/// List of all PlayableAssets
/// </summary>
public static IEnumerable<Type> AllClipTypes()
{
if (s_AllClipTypes == null)
{
s_AllClipTypes = TypeCache.GetTypesDerivedFrom<IPlayableAsset>().
Where(t => IsConcreteAsset(t)).
ToArray();
}
return s_AllClipTypes;
}
public static IEnumerable<Type> AllTrackTypes()
{
if (s_AllTrackTypes == null)
{
s_AllTrackTypes = TypeCache.GetTypesDerivedFrom<TrackAsset>()
.Where(x => !x.IsAbstract)
.ToArray();
}
return s_AllTrackTypes;
}
public static IEnumerable<Type> GetVisiblePlayableAssetsHandledByTrack(Type trackType)
{
if (trackType == null || !typeof(TrackAsset).IsAssignableFrom(trackType))
return Enumerable.Empty<Type>();
Type[] types;
if (s_TrackTypeToVisibleClipType.TryGetValue(trackType, out types))
{
return types;
}
// special case -- the playable track handles all types not handled by other tracks
if (trackType == typeof(PlayableTrack))
{
types = GetUnhandledClipTypes().ToArray();
s_TrackTypeToVisibleClipType[trackType] = types;
return types;
}
var attributes = trackType.GetCustomAttributes(typeof(TrackClipTypeAttribute), true);
var baseClasses = attributes.
OfType<TrackClipTypeAttribute>().
Where(t => t.allowAutoCreate).
Select(a => a.inspectedType);
types = AllClipTypes().Where(t => baseClasses.Any(x => x.IsAssignableFrom(t))).ToArray();
s_TrackTypeToVisibleClipType[trackType] = types;
return types;
}
public static IEnumerable<Type> GetPlayableAssetsHandledByTrack(Type trackType)
{
if (trackType == null || !typeof(TrackAsset).IsAssignableFrom(trackType))
return Enumerable.Empty<Type>();
Type[] types;
if (s_TrackTypeToAllClipType.TryGetValue(trackType, out types))
{
return types;
}
// special case -- the playable track handles all types not handled by other tracks
if (trackType == typeof(PlayableTrack))
{
types = GetUnhandledClipTypes().ToArray();
s_TrackTypeToAllClipType[trackType] = types;
return types;
}
var attributes = trackType.GetCustomAttributes(typeof(TrackClipTypeAttribute), true);
var baseClasses = attributes.
OfType<TrackClipTypeAttribute>().
Select(a => a.inspectedType);
types = AllClipTypes().Where(t => baseClasses.Any(x => x.IsAssignableFrom(t))).ToArray();
s_TrackTypeToAllClipType[trackType] = types;
return types;
}
/// <summary>
/// Returns the binding attribute attrached to the track
/// </summary>
public static TrackBindingTypeAttribute GetTrackBindingAttribute(Type trackType)
{
if (trackType == null || !typeof(TrackAsset).IsAssignableFrom(trackType))
return null;
TrackBindingTypeAttribute attribute = null;
if (!s_TrackToBindingCache.TryGetValue(trackType, out attribute))
{
attribute = (TrackBindingTypeAttribute)Attribute.GetCustomAttribute(trackType, typeof(TrackBindingTypeAttribute));
s_TrackToBindingCache.Add(trackType, attribute);
}
return attribute;
}
/// <summary>
/// True if the given track has a clip type that handles the given object
/// </summary>
public static bool TrackHasClipForObject(Type trackType, Object obj)
{
return GetPlayableAssetsHandledByTrack(trackType)
.Any(c => ObjectReferenceField.FindObjectReferences(c).Any(o => o.IsAssignable(obj)));
}
/// <summary>
/// Get the list of markers that have fields for the object
/// </summary>
public static IEnumerable<Type> MarkerTypesWithFieldForObject(Object obj)
{
return GetAllMarkerTypes().Where(
c => ObjectReferenceField.FindObjectReferences(c).Any(o => o.IsAssignable(obj))
);
}
/// <summary>
/// Get the list of tracks that can handle this object as clips
/// </summary>
public static IEnumerable<Type> GetTrackTypesForObject(Object obj)
{
if (obj == null)
return Enumerable.Empty<Type>();
return AllTrackTypes().Where(t => TrackHasClipForObject(t, obj));
}
/// <summary>
/// Given a trackType and an object, does the binding type match
/// Takes into account whether creating a missing component is permitted
/// </summary>
public static bool IsTrackCreatableFromObject(Object obj, Type trackType)
{
if (obj == null || obj.IsPrefab())
return false;
var attribute = GetTrackBindingAttribute(trackType);
if (attribute == null || attribute.type == null)
return false;
if (attribute.type.IsAssignableFrom(obj.GetType()))
return true;
var gameObject = obj as GameObject;
if (gameObject != null && typeof(Component).IsAssignableFrom(attribute.type))
{
return gameObject.GetComponent(attribute.type) != null ||
(attribute.flags & TrackBindingFlags.AllowCreateComponent) != 0;
}
return false;
}
/// <summary>
/// Given an object, get the list of track that are creatable from it. Takes
/// binding flags into account
/// </summary>
public static IEnumerable<Type> GetTracksCreatableFromObject(Object obj)
{
if (obj == null)
return Enumerable.Empty<Type>();
return AllTrackTypes().Where(t => !IsHiddenInMenu(t) && IsTrackCreatableFromObject(obj, t));
}
/// <summary>
/// Get the list of playable assets that can handle an object for a particular track
/// </summary>
/// <param name="trackType">The type of the track</param>
/// <param name="obj">The object to handle</param>
/// <returns></returns>
public static IEnumerable<Type> GetAssetTypesForObject(Type trackType, Object obj)
{
if (obj == null)
return Enumerable.Empty<Type>();
return GetPlayableAssetsHandledByTrack(trackType).Where(
c => ObjectReferenceField.FindObjectReferences(c).Any(o => o.IsAssignable(obj))
);
}
// get the track types for a track from it's attributes
private static IEnumerable<Type> GetTrackClipTypesFromAttributes(Type trackType)
{
if (trackType == null || !typeof(TrackAsset).IsAssignableFrom(trackType))
return Enumerable.Empty<Type>();
var attributes = trackType.GetCustomAttributes(typeof(TrackClipTypeAttribute), true);
var baseClasses = attributes.
OfType<TrackClipTypeAttribute>().
Select(a => a.inspectedType);
return AllClipTypes().Where(t => baseClasses.Any(x => x.IsAssignableFrom(t)));
}
// find the playable asset types that are unhandled
private static IEnumerable<Type> GetUnhandledClipTypes()
{
var typesHandledByTrack = AllTrackTypes().SelectMany(t => GetTrackClipTypesFromAttributes(t));
// exclude anything in the timeline assembly, handled by tracks, has a hide in menu attribute
// or is explicity ignored
return AllClipTypes()
.Except(typesHandledByTrack)
.Where(t => !TypeUtility.IsBuiltIn(t)) // exclude built-in
.Where(t => !typeof(TrackAsset).IsAssignableFrom(t)) // exclude track types (they are playable assets)
.Where(t => !t.IsDefined(typeof(HideInMenuAttribute), false) && !t.IsDefined(typeof(IgnoreOnPlayableTrackAttribute), true))
.Distinct();
}
public static IEnumerable<Type> GetAllMarkerTypes()
{
if (s_MarkerTypes == null)
{
s_MarkerTypes = TypeCache.GetTypesDerivedFrom<IMarker>()
.Where(x =>
typeof(ScriptableObject).IsAssignableFrom(x)
&& !x.IsAbstract
&& !x.IsGenericType
&& !x.IsInterface)
.ToArray();
}
return s_MarkerTypes;
}
public static IEnumerable<Type> GetUserMarkerTypes()
{
return GetAllMarkerTypes().Where(x => !IsBuiltIn(x) && !IsHiddenInMenu(x));
}
public static IEnumerable<Type> GetBuiltInMarkerTypes()
{
return GetAllMarkerTypes().Where(TypeUtility.IsBuiltIn);
}
public static bool DoesTrackSupportMarkerType(TrackAsset track, Type type)
{
if (track.supportsNotifications)
{
return true;
}
return !typeof(INotification).IsAssignableFrom(type);
}
internal static string GetDisplayName(Type t)
{
var displayName = ObjectNames.NicifyVariableName(t.Name);
var attr = Attribute.GetCustomAttribute(t, typeof(DisplayNameAttribute), false) as DisplayNameAttribute;
if (attr != null)
displayName = attr.DisplayName;
return L10n.Tr(displayName);
}
public static bool IsHiddenInMenu(Type type)
{
var attr = type.GetCustomAttributes(typeof(HideInMenuAttribute), false);
return attr.Length > 0;
}
public struct ObjectReference
{
public Type type;
public bool isSceneReference;
}
public static IEnumerable<ObjectReference> ObjectReferencesForType(Type type)
{
var objectReferences = ObjectReferenceField.FindObjectReferences(type);
var uniqueTypes = objectReferences.Select(objRef => objRef.type).Distinct();
foreach (var refType in uniqueTypes)
{
var isSceneReference = objectReferences.Any(objRef => objRef.type == refType && objRef.isSceneReference);
yield return new ObjectReference { type = refType, isSceneReference = isSceneReference };
}
}
/// <summary>
/// Checks whether a type has an overridden method with a specific name. This method also checks overridden members in parent classes.
/// </summary>
public static bool HasOverrideMethod(System.Type t, string name)
{
const MethodAttributes mask = MethodAttributes.Virtual | MethodAttributes.NewSlot;
const MethodAttributes expectedResult = MethodAttributes.Virtual;
var method = t.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
return method != null && (method.Attributes & mask) == expectedResult;
}
/// <summary>
/// Returns whether the given type resides in the timeline assembly
/// </summary>
public static bool IsBuiltIn(System.Type t)
{
return t != null && t.Assembly.Equals(typeof(TimelineAsset).Assembly);
}
}
}