2022-01-12 10:06:03 +03:00
using System ;
using System.Collections.Generic ;
using UnityEngine ;
using UnityEngine.Timeline ;
using UnityEngine.Playables ;
using UnityEngineInternal ; // for metro type extensions
namespace UnityEngine.Timeline
{
public partial class TimelineAsset
{
/// <summary>
/// Allows you to create a track and add it to the Timeline.
/// </summary>
/// <param name="type">The type of track to create. Must derive from TrackAsset.</param>
/// <param name="parent">Track to parent to. This can be null.</param>
/// <param name="name">Name to give the track.</param>
/// <returns>The created track.</returns>
/// <remarks>
/// This method will throw an InvalidOperationException if the parent is not valid. The parent can be any GroupTrack, or a supported parent type of track. For example, this can be used to create override tracks in AnimationTracks.
/// </remarks>
public TrackAsset CreateTrack ( Type type , TrackAsset parent , string name )
{
if ( parent ! = null & & parent . timelineAsset ! = this )
throw new InvalidOperationException ( "Addtrack cannot parent to a track not in the Timeline" ) ;
if ( ! typeof ( TrackAsset ) . IsAssignableFrom ( type ) )
throw new InvalidOperationException ( "Supplied type must be a track asset" ) ;
if ( parent ! = null )
{
if ( ! TimelineCreateUtilities . ValidateParentTrack ( parent , type ) )
throw new InvalidOperationException ( "Cannot assign a child of type " + type . Name + " to a parent of type " + parent . GetType ( ) . Name ) ;
}
var actualParent = parent ! = null ? parent as PlayableAsset : this ;
TimelineUndo . PushUndo ( actualParent , "Create Track" ) ;
var baseName = name ;
if ( string . IsNullOrEmpty ( baseName ) )
{
baseName = type . Name ;
#if UNITY_EDITOR
baseName = UnityEditor . ObjectNames . NicifyVariableName ( baseName ) ;
#endif
}
var trackName = baseName ;
if ( parent ! = null )
trackName = TimelineCreateUtilities . GenerateUniqueActorName ( parent . subTracksObjects , baseName ) ;
else
trackName = TimelineCreateUtilities . GenerateUniqueActorName ( trackObjects , baseName ) ;
TrackAsset newTrack = AllocateTrack ( parent , trackName , type ) ;
if ( newTrack ! = null )
{
newTrack . name = trackName ;
TimelineCreateUtilities . SaveAssetIntoObject ( newTrack , actualParent ) ;
}
return newTrack ;
}
/// <summary>
/// Creates a track and adds it to the Timeline Asset.
/// </summary>
/// <param name="parent">Track to parent to. This can be null.</param>
/// <param name="trackName">The name of the track being created.</param>
/// <typeparam name="T">The type of track being created. The track type must be derived from TrackAsset.</typeparam>
/// <returns>Returns the created track.</returns>
/// <remarks>
/// This method will throw an InvalidOperationException if the parent is not valid. The parent can be any GroupTrack, or a supported parent type of track. For example, this can be used to create override tracks in AnimationTracks.
/// </remarks>
public T CreateTrack < T > ( TrackAsset parent , string trackName ) where T : TrackAsset , new ( )
{
return ( T ) CreateTrack ( typeof ( T ) , parent , trackName ) ;
}
/// <summary>
/// Creates a track and adds it to the Timeline Asset.
/// </summary>
/// <param name="trackName">The name of the track being created.</param>
/// <typeparam name="T">The type of track being created. The track type must be derived from TrackAsset.</typeparam>
/// <returns>Returns the created track.</returns>
public T CreateTrack < T > ( string trackName ) where T : TrackAsset , new ( )
{
return ( T ) CreateTrack ( typeof ( T ) , null , trackName ) ;
}
/// <summary>
/// Creates a track and adds it to the Timeline Asset.
/// </summary>
/// <typeparam name="T">The type of track being created. The track type must be derived from TrackAsset.</typeparam>
/// <returns>Returns the created track.</returns>
public T CreateTrack < T > ( ) where T : TrackAsset , new ( )
{
return ( T ) CreateTrack ( typeof ( T ) , null , null ) ;
}
/// <summary>
/// Delete a clip from this timeline.
/// </summary>
/// <param name="clip">The clip to delete.</param>
/// <returns>Returns true if the removal was successful</returns>
/// <remarks>
/// This method will delete a clip and any assets owned by the clip.
/// </remarks>
public bool DeleteClip ( TimelineClip clip )
{
if ( clip = = null | | clip . parentTrack = = null )
{
return false ;
}
if ( this ! = clip . parentTrack . timelineAsset )
{
Debug . LogError ( "Cannot delete a clip from this timeline" ) ;
return false ;
}
TimelineUndo . PushUndo ( clip . parentTrack , "Delete Clip" ) ;
if ( clip . curves ! = null )
{
2022-01-12 10:39:15 +03:00
TimelineUndo . PushDestroyUndo ( this , clip . parentTrack , clip . curves ) ;
2022-01-12 10:06:03 +03:00
}
// handle wrapped assets
if ( clip . asset ! = null )
{
DeleteRecordedAnimation ( clip ) ;
// TODO -- we should flag assets and owned, instead of this check...
#if UNITY_EDITOR
string path = UnityEditor . AssetDatabase . GetAssetPath ( clip . asset ) ;
if ( path = = UnityEditor . AssetDatabase . GetAssetPath ( this ) )
#endif
{
2022-01-12 10:39:15 +03:00
TimelineUndo . PushDestroyUndo ( this , clip . parentTrack , clip . asset ) ;
2022-01-12 10:06:03 +03:00
}
}
var clipParentTrack = clip . parentTrack ;
clipParentTrack . RemoveClip ( clip ) ;
clipParentTrack . CalculateExtrapolationTimes ( ) ;
return true ;
}
/// <summary>
/// Deletes a track from a timeline, including all clips and subtracks.
/// </summary>
/// <param name="track">The track to delete. It must be owned by this Timeline.</param>
/// <returns>True if the track was deleted successfully.</returns>
public bool DeleteTrack ( TrackAsset track )
{
if ( track . timelineAsset ! = this )
return false ;
// push before we modify properties
TimelineUndo . PushUndo ( track , "Delete Track" ) ;
TimelineUndo . PushUndo ( this , "Delete Track" ) ;
TrackAsset parent = track . parent as TrackAsset ;
if ( parent ! = null )
TimelineUndo . PushUndo ( parent , "Delete Track" ) ;
var children = track . GetChildTracks ( ) ;
foreach ( var child in children )
{
DeleteTrack ( child ) ;
}
DeleteRecordedAnimation ( track ) ;
var clipsToDelete = new List < TimelineClip > ( track . clips ) ;
foreach ( var clip in clipsToDelete )
{
DeleteClip ( clip ) ;
}
RemoveTrack ( track ) ;
2022-01-12 10:39:15 +03:00
TimelineUndo . PushDestroyUndo ( this , this , track ) ;
2022-01-12 10:06:03 +03:00
return true ;
}
internal void MoveLastTrackBefore ( TrackAsset asset )
{
if ( m_Tracks = = null | | m_Tracks . Count < 2 | | asset = = null )
return ;
var lastTrack = m_Tracks [ m_Tracks . Count - 1 ] ;
if ( lastTrack = = asset )
return ;
for ( int i = 0 ; i < m_Tracks . Count - 1 ; i + + )
{
if ( m_Tracks [ i ] = = asset )
{
for ( int j = m_Tracks . Count - 1 ; j > i ; j - - )
m_Tracks [ j ] = m_Tracks [ j - 1 ] ;
m_Tracks [ i ] = lastTrack ;
Invalidate ( ) ;
break ;
}
}
}
internal TrackAsset AllocateTrack ( TrackAsset trackAssetParent , string trackName , Type trackType )
{
if ( trackAssetParent ! = null & & trackAssetParent . timelineAsset ! = this )
throw new InvalidOperationException ( "Addtrack cannot parent to a track not in the Timeline" ) ;
if ( ! typeof ( TrackAsset ) . IsAssignableFrom ( trackType ) )
throw new InvalidOperationException ( "Supplied type must be a track asset" ) ;
var asset = ( TrackAsset ) CreateInstance ( trackType ) ;
asset . name = trackName ;
if ( trackAssetParent ! = null )
trackAssetParent . AddChild ( asset ) ;
else
AddTrackInternal ( asset ) ;
return asset ;
}
void DeleteRecordedAnimation ( TrackAsset track )
{
var animTrack = track as AnimationTrack ;
if ( animTrack ! = null & & animTrack . infiniteClip ! = null )
2022-01-12 10:39:15 +03:00
TimelineUndo . PushDestroyUndo ( this , track , animTrack . infiniteClip ) ;
2022-01-12 10:06:03 +03:00
if ( track . curves ! = null )
2022-01-12 10:39:15 +03:00
TimelineUndo . PushDestroyUndo ( this , track , track . curves ) ;
2022-01-12 10:06:03 +03:00
}
void DeleteRecordedAnimation ( TimelineClip clip )
{
if ( clip = = null )
return ;
if ( clip . curves ! = null )
2022-01-12 10:39:15 +03:00
TimelineUndo . PushDestroyUndo ( this , clip . parentTrack , clip . curves ) ;
2022-01-12 10:06:03 +03:00
if ( ! clip . recordable )
return ;
AnimationPlayableAsset asset = clip . asset as AnimationPlayableAsset ;
if ( asset = = null | | asset . clip = = null )
return ;
2022-01-12 10:39:15 +03:00
TimelineUndo . PushDestroyUndo ( this , asset , asset . clip ) ;
2022-01-12 10:06:03 +03:00
}
}
}