You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
314 lines
12 KiB
314 lines
12 KiB
using System; |
|
using System.Globalization; |
|
using System.Collections.Generic; |
|
using System.Linq; |
|
#if UNITY_2021_2_OR_NEWER |
|
using UnityEditor.SceneManagement; |
|
#else |
|
using UnityEditor.Experimental.SceneManagement; |
|
#endif |
|
using UnityEngine; |
|
using UnityEngine.Timeline; |
|
using UnityEngine.Playables; |
|
using Object = UnityEngine.Object; |
|
|
|
|
|
namespace UnityEditor.Timeline |
|
{ |
|
static class TimelineUtility |
|
{ |
|
public static void ReorderTracks(List<ScriptableObject> allTracks, List<TrackAsset> tracks, ScriptableObject insertAfterAsset, bool up) |
|
{ |
|
foreach (var i in tracks) |
|
allTracks.Remove(i); |
|
|
|
int index = allTracks.IndexOf(insertAfterAsset); |
|
|
|
index = up ? Math.Max(index, 0) : index + 1; |
|
|
|
allTracks.InsertRange(index, tracks.OfType<ScriptableObject>()); |
|
} |
|
|
|
// Gets the track that holds the game object reference for this track. |
|
public static TrackAsset GetSceneReferenceTrack(TrackAsset asset) |
|
{ |
|
if (asset == null) |
|
return null; |
|
if (asset.isSubTrack) |
|
return GetSceneReferenceTrack(asset.parent as TrackAsset); |
|
return asset; |
|
} |
|
|
|
public static bool TrackHasAnimationCurves(TrackAsset track) |
|
{ |
|
if (track.hasCurves) |
|
return true; |
|
|
|
var animTrack = track as AnimationTrack; |
|
if (animTrack != null && animTrack.infiniteClip != null && !animTrack.infiniteClip.empty) |
|
return true; |
|
|
|
for (int i = 0; i < track.clips.Length; i++) |
|
{ |
|
var curveClip = track.clips[i].curves; |
|
var animationClip = track.clips[i].animationClip; |
|
|
|
// prune out clip with zero curves |
|
if (curveClip != null && curveClip.empty) |
|
curveClip = null; |
|
|
|
if (animationClip != null && animationClip.empty) |
|
animationClip = null; |
|
|
|
// prune out clips coming from FBX |
|
if (animationClip != null && ((animationClip.hideFlags & HideFlags.NotEditable) != 0)) |
|
animationClip = null; |
|
|
|
if (!track.clips[i].recordable) |
|
animationClip = null; |
|
|
|
if ((curveClip != null) || (animationClip != null)) |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
// get the game object reference associated with this |
|
public static GameObject GetSceneGameObject(PlayableDirector director, TrackAsset asset) |
|
{ |
|
if (director == null || asset == null) |
|
return null; |
|
|
|
asset = GetSceneReferenceTrack(asset); |
|
|
|
var gameObject = director.GetGenericBinding(asset) as GameObject; |
|
var component = director.GetGenericBinding(asset) as Component; |
|
if (component != null) |
|
gameObject = component.gameObject; |
|
return gameObject; |
|
} |
|
|
|
public static PlayableDirector[] GetDirectorsInSceneUsingAsset(PlayableAsset asset) |
|
{ |
|
const HideFlags hideFlags = |
|
HideFlags.HideInHierarchy | HideFlags.HideInInspector | |
|
HideFlags.DontSaveInEditor | HideFlags.NotEditable; |
|
|
|
var prefabMode = PrefabStageUtility.GetCurrentPrefabStage(); |
|
|
|
var inScene = new List<PlayableDirector>(); |
|
var allDirectors = Resources.FindObjectsOfTypeAll(typeof(PlayableDirector)) as PlayableDirector[]; |
|
foreach (var director in allDirectors) |
|
{ |
|
if ((director.hideFlags & hideFlags) != 0) |
|
continue; |
|
|
|
string assetPath = AssetDatabase.GetAssetPath(director.transform.root.gameObject); |
|
if (!String.IsNullOrEmpty(assetPath)) |
|
continue; |
|
|
|
if (prefabMode != null && !prefabMode.IsPartOfPrefabContents(director.gameObject)) |
|
continue; |
|
|
|
if (asset == null || (asset != null && director.playableAsset == asset)) |
|
{ |
|
inScene.Add(director); |
|
} |
|
} |
|
return inScene.ToArray(); |
|
} |
|
|
|
public static PlayableDirector GetDirectorComponentForGameObject(GameObject gameObject) |
|
{ |
|
return gameObject != null ? gameObject.GetComponent<PlayableDirector>() : null; |
|
} |
|
|
|
public static TimelineAsset GetTimelineAssetForDirectorComponent(PlayableDirector director) |
|
{ |
|
return director != null ? director.playableAsset as TimelineAsset : null; |
|
} |
|
|
|
public static bool IsPrefabOrAsset(Object obj) |
|
{ |
|
return EditorUtility.IsPersistent(obj) || (obj.hideFlags & HideFlags.NotEditable) != 0; |
|
} |
|
|
|
// TODO -- Need to add this to SerializedProperty so we can get replicate the accuracy that exists |
|
// in the undo system |
|
internal static string PropertyToString(SerializedProperty property) |
|
{ |
|
switch (property.propertyType) |
|
{ |
|
case SerializedPropertyType.Integer: |
|
return property.intValue.ToString(CultureInfo.InvariantCulture); |
|
case SerializedPropertyType.Float: |
|
return property.floatValue.ToString(CultureInfo.InvariantCulture); |
|
case SerializedPropertyType.String: |
|
return property.stringValue; |
|
case SerializedPropertyType.Boolean: |
|
return property.boolValue ? "1" : "0"; |
|
case SerializedPropertyType.Color: |
|
return property.colorValue.ToString(); |
|
case SerializedPropertyType.ArraySize: |
|
return property.intValue.ToString(CultureInfo.InvariantCulture); |
|
case SerializedPropertyType.Enum: |
|
return property.intValue.ToString(CultureInfo.InvariantCulture); |
|
case SerializedPropertyType.ObjectReference: |
|
return string.Empty; |
|
case SerializedPropertyType.LayerMask: |
|
return property.intValue.ToString(CultureInfo.InvariantCulture); |
|
case SerializedPropertyType.Character: |
|
return property.intValue.ToString(CultureInfo.InvariantCulture); |
|
case SerializedPropertyType.AnimationCurve: |
|
return property.animationCurveValue.ToString(); |
|
case SerializedPropertyType.Gradient: |
|
return property.gradientValue.ToString(); |
|
case SerializedPropertyType.Vector3: |
|
return property.vector3Value.ToString(); |
|
case SerializedPropertyType.Vector4: |
|
return property.vector4Value.ToString(); |
|
case SerializedPropertyType.Vector2: |
|
return property.vector2Value.ToString(); |
|
case SerializedPropertyType.Rect: |
|
return property.rectValue.ToString(); |
|
case SerializedPropertyType.Bounds: |
|
return property.boundsValue.ToString(); |
|
case SerializedPropertyType.Quaternion: |
|
return property.quaternionValue.ToString(); |
|
case SerializedPropertyType.Generic: |
|
return string.Empty; |
|
default: |
|
Debug.LogWarning("Unknown Property Type: " + property.propertyType); |
|
return string.Empty; |
|
} |
|
} |
|
|
|
// Is this a recordable clip on an animation track. |
|
internal static bool IsRecordableAnimationClip(TimelineClip clip) |
|
{ |
|
if (!clip.recordable) |
|
return false; |
|
|
|
AnimationPlayableAsset asset = clip.asset as AnimationPlayableAsset; |
|
if (asset == null) |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
public static bool HasCustomEditor(TimelineClip clip) |
|
{ |
|
var editor = CustomTimelineEditorCache.GetClipEditor(clip); |
|
return editor != CustomTimelineEditorCache.GetDefaultClipEditor(); |
|
} |
|
|
|
public static IList<PlayableDirector> GetSubTimelines(TimelineClip clip, IExposedPropertyTable director) |
|
{ |
|
var editor = CustomTimelineEditorCache.GetClipEditor(clip); |
|
List<PlayableDirector> directors = new List<PlayableDirector>(); |
|
try |
|
{ |
|
editor.GetSubTimelines(clip, director as PlayableDirector, directors); |
|
} |
|
catch (Exception e) |
|
{ |
|
Debug.LogException(e); |
|
} |
|
|
|
return directors; |
|
} |
|
|
|
public static bool IsAllSubTrackMuted(TrackAsset asset) |
|
{ |
|
if (asset is GroupTrack) |
|
return asset.mutedInHierarchy; |
|
|
|
foreach (TrackAsset t in asset.GetChildTracks()) |
|
{ |
|
if (!t.muted) |
|
return false; |
|
|
|
var childMuted = IsAllSubTrackMuted(t); |
|
|
|
if (!childMuted) |
|
return false; |
|
} |
|
return true; |
|
} |
|
|
|
public static bool IsParentMuted(TrackAsset asset) |
|
{ |
|
TrackAsset p = asset.parent as TrackAsset; |
|
if (p == null) return false; |
|
return p is GroupTrack ? p.mutedInHierarchy : IsParentMuted(p); |
|
} |
|
|
|
public static IEnumerable<PlayableDirector> GetAllDirectorsInHierarchy(PlayableDirector mainDirector) |
|
{ |
|
var directors = new HashSet<PlayableDirector> { mainDirector }; |
|
GetAllDirectorsInHierarchy(mainDirector, directors); |
|
return directors; |
|
} |
|
|
|
static void GetAllDirectorsInHierarchy(PlayableDirector director, ISet<PlayableDirector> directors) |
|
{ |
|
var timelineAsset = director.playableAsset as TimelineAsset; |
|
if (timelineAsset == null) |
|
return; |
|
|
|
foreach (var track in timelineAsset.GetOutputTracks()) |
|
{ |
|
foreach (var clip in track.clips) |
|
{ |
|
foreach (var subDirector in GetSubTimelines(clip, director)) |
|
{ |
|
if (!directors.Contains(subDirector)) |
|
{ |
|
directors.Add(subDirector); |
|
GetAllDirectorsInHierarchy(subDirector, directors); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
public static IEnumerable<T> GetBindingsFromDirectors<T>(IEnumerable<PlayableDirector> directors) where T : Object |
|
{ |
|
var bindings = new HashSet<T>(); |
|
foreach (var director in directors) |
|
{ |
|
if (director.playableAsset == null) continue; |
|
foreach (var output in director.playableAsset.outputs) |
|
{ |
|
var binding = director.GetGenericBinding(output.sourceObject) as T; |
|
if (binding != null) |
|
bindings.Add(binding); |
|
} |
|
} |
|
return bindings; |
|
} |
|
|
|
public static bool IsLockedFromGroup(TrackAsset asset) |
|
{ |
|
TrackAsset p = asset.parent as TrackAsset; |
|
if (p == null) return false; |
|
return p is GroupTrack ? p.lockedInHierarchy : IsLockedFromGroup(p); |
|
} |
|
|
|
internal static bool IsCurrentSequenceValid() |
|
{ |
|
return TimelineWindow.instance != null |
|
&& TimelineWindow.instance.state != null |
|
&& TimelineWindow.instance.state.editSequence != null; |
|
} |
|
|
|
public static TimelineAsset CreateAndSaveTimelineAsset(string path) |
|
{ |
|
var newAsset = ScriptableObject.CreateInstance<TimelineAsset>(); |
|
newAsset.editorSettings.frameRate = TimelineProjectSettings.instance.defaultFrameRate; |
|
AssetDatabase.CreateAsset(newAsset, path); |
|
return newAsset; |
|
} |
|
} |
|
}
|
|
|