A game about forced loneliness, made by TACStudios
1using System;
2using System.Collections.Generic;
3using UnityEngine;
4using UnityEngine.Timeline;
5using UnityEngine.Playables;
6using UnityEngineInternal; // for metro type extensions
7
8namespace UnityEngine.Timeline
9{
10 public partial class TimelineAsset
11 {
12 /// <summary>
13 /// Allows you to create a track and add it to the Timeline.
14 /// </summary>
15 /// <param name="type">The type of track to create. Must derive from TrackAsset.</param>
16 /// <param name="parent">Track to parent to. This can be null.</param>
17 /// <param name="name">Name to give the track.</param>
18 /// <returns>The created track.</returns>
19 /// <remarks>
20 /// 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.
21 /// </remarks>
22 public TrackAsset CreateTrack(Type type, TrackAsset parent, string name)
23 {
24 if (parent != null && parent.timelineAsset != this)
25 throw new InvalidOperationException("Addtrack cannot parent to a track not in the Timeline");
26
27 if (!typeof(TrackAsset).IsAssignableFrom(type))
28 throw new InvalidOperationException("Supplied type must be a track asset");
29
30 if (parent != null)
31 {
32 if (!TimelineCreateUtilities.ValidateParentTrack(parent, type))
33 throw new InvalidOperationException("Cannot assign a child of type " + type.Name + " to a parent of type " + parent.GetType().Name);
34 }
35
36 var baseName = name;
37 if (string.IsNullOrEmpty(baseName))
38 {
39 baseName = type.Name;
40#if UNITY_EDITOR
41 baseName = UnityEditor.ObjectNames.NicifyVariableName(baseName);
42#endif
43 }
44
45 var trackName = baseName;
46 if (parent != null)
47 trackName = TimelineCreateUtilities.GenerateUniqueActorName(parent.subTracksObjects, baseName);
48 else
49 trackName = TimelineCreateUtilities.GenerateUniqueActorName(trackObjects, baseName);
50
51 TrackAsset newTrack = AllocateTrack(parent, trackName, type);
52
53 return newTrack;
54 }
55
56 /// <summary>
57 /// Creates a track and adds it to the Timeline Asset.
58 /// </summary>
59 /// <param name="parent">Track to parent to. This can be null.</param>
60 /// <param name="trackName">The name of the track being created.</param>
61 /// <typeparam name="T">The type of track being created. The track type must be derived from TrackAsset.</typeparam>
62 /// <returns>Returns the created track.</returns>
63 /// <remarks>
64 /// 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.
65 /// </remarks>
66 public T CreateTrack<T>(TrackAsset parent, string trackName) where T : TrackAsset, new()
67 {
68 return (T)CreateTrack(typeof(T), parent, trackName);
69 }
70
71 /// <summary>
72 /// Creates a track and adds it to the Timeline Asset.
73 /// </summary>
74 /// <param name="trackName">The name of the track being created.</param>
75 /// <typeparam name="T">The type of track being created. The track type must be derived from TrackAsset.</typeparam>
76 /// <returns>Returns the created track.</returns>
77 public T CreateTrack<T>(string trackName) where T : TrackAsset, new()
78 {
79 return (T)CreateTrack(typeof(T), null, trackName);
80 }
81
82 /// <summary>
83 /// Creates a track and adds it to the Timeline Asset.
84 /// </summary>
85 /// <typeparam name="T">The type of track being created. The track type must be derived from TrackAsset.</typeparam>
86 /// <returns>Returns the created track.</returns>
87 public T CreateTrack<T>() where T : TrackAsset, new()
88 {
89 return (T)CreateTrack(typeof(T), null, null);
90 }
91
92 /// <summary>
93 /// Delete a clip from this timeline.
94 /// </summary>
95 /// <param name="clip">The clip to delete.</param>
96 /// <returns>Returns true if the removal was successful</returns>
97 /// <remarks>
98 /// This method will delete a clip and any assets owned by the clip.
99 /// </remarks>
100 public bool DeleteClip(TimelineClip clip)
101 {
102 if (clip == null || clip.GetParentTrack() == null)
103 {
104 return false;
105 }
106 if (this != clip.GetParentTrack().timelineAsset)
107 {
108 Debug.LogError("Cannot delete a clip from this timeline");
109 return false;
110 }
111
112 TimelineUndo.PushUndo(clip.GetParentTrack(), "Delete Clip");
113 if (clip.curves != null)
114 {
115 TimelineUndo.PushDestroyUndo(this, clip.GetParentTrack(), clip.curves);
116 }
117
118 // handle wrapped assets
119 if (clip.asset != null)
120 {
121 DeleteRecordedAnimation(clip);
122
123 // TODO -- we should flag assets and owned, instead of this check...
124#if UNITY_EDITOR
125 string path = UnityEditor.AssetDatabase.GetAssetPath(clip.asset);
126 if (path == UnityEditor.AssetDatabase.GetAssetPath(this))
127#endif
128 {
129 TimelineUndo.PushDestroyUndo(this, clip.GetParentTrack(), clip.asset);
130 }
131 }
132
133 var clipParentTrack = clip.GetParentTrack();
134 clipParentTrack.RemoveClip(clip);
135 clipParentTrack.CalculateExtrapolationTimes();
136
137 return true;
138 }
139
140 /// <summary>
141 /// Deletes a track from a timeline, including all clips and subtracks.
142 /// </summary>
143 /// <param name="track">The track to delete. It must be owned by this Timeline.</param>
144 /// <returns>True if the track was deleted successfully.</returns>
145 public bool DeleteTrack(TrackAsset track)
146 {
147 if (track.timelineAsset != this)
148 return false;
149
150 // push before we modify properties
151 TimelineUndo.PushUndo(track, "Delete Track");
152 TimelineUndo.PushUndo(this, "Delete Track");
153
154 TrackAsset parent = track.parent as TrackAsset;
155 if (parent != null)
156 TimelineUndo.PushUndo(parent, "Delete Track");
157
158 var children = track.GetChildTracks();
159 foreach (var child in children)
160 {
161 DeleteTrack(child);
162 }
163
164 DeleteRecordedAnimation(track);
165
166 var clipsToDelete = new List<TimelineClip>(track.clips);
167 foreach (var clip in clipsToDelete)
168 {
169 DeleteClip(clip);
170 }
171 RemoveTrack(track);
172
173 TimelineUndo.PushDestroyUndo(this, this, track);
174
175 return true;
176 }
177
178 internal void MoveLastTrackBefore(TrackAsset asset)
179 {
180 if (m_Tracks == null || m_Tracks.Count < 2 || asset == null)
181 return;
182
183 var lastTrack = m_Tracks[m_Tracks.Count - 1];
184 if (lastTrack == asset)
185 return;
186
187 for (int i = 0; i < m_Tracks.Count - 1; i++)
188 {
189 if (m_Tracks[i] == asset)
190 {
191 for (int j = m_Tracks.Count - 1; j > i; j--)
192 m_Tracks[j] = m_Tracks[j - 1];
193 m_Tracks[i] = lastTrack;
194 Invalidate();
195 break;
196 }
197 }
198 }
199
200 TrackAsset AllocateTrack(TrackAsset trackAssetParent, string trackName, Type trackType)
201 {
202 if (trackAssetParent != null && trackAssetParent.timelineAsset != this)
203 throw new InvalidOperationException("Addtrack cannot parent to a track not in the Timeline");
204
205 if (!typeof(TrackAsset).IsAssignableFrom(trackType))
206 throw new InvalidOperationException("Supplied type must be a track asset");
207
208 var asset = (TrackAsset)CreateInstance(trackType);
209 asset.name = trackName;
210
211 const string createTrackUndoName = "Create Track";
212
213 PlayableAsset parent = trackAssetParent != null ? trackAssetParent as PlayableAsset : this;
214 TimelineCreateUtilities.SaveAssetIntoObject(asset, parent);
215 TimelineUndo.RegisterCreatedObjectUndo(asset, createTrackUndoName);
216 TimelineUndo.PushUndo(parent, createTrackUndoName);
217
218 if (trackAssetParent != null)
219 trackAssetParent.AddChild(asset);
220 else //TimelineAsset is the parent
221 AddTrackInternal(asset);
222
223 return asset;
224 }
225
226 void DeleteRecordedAnimation(TrackAsset track)
227 {
228 var animTrack = track as AnimationTrack;
229 if (animTrack != null && animTrack.infiniteClip != null)
230 TimelineUndo.PushDestroyUndo(this, track, animTrack.infiniteClip);
231
232 if (track.curves != null)
233 TimelineUndo.PushDestroyUndo(this, track, track.curves);
234 }
235
236 void DeleteRecordedAnimation(TimelineClip clip)
237 {
238 if (clip == null)
239 return;
240
241 if (clip.curves != null)
242 TimelineUndo.PushDestroyUndo(this, clip.GetParentTrack(), clip.curves);
243
244 if (!clip.recordable)
245 return;
246
247 AnimationPlayableAsset asset = clip.asset as AnimationPlayableAsset;
248 if (asset == null || asset.clip == null)
249 return;
250
251 TimelineUndo.PushDestroyUndo(this, asset, asset.clip);
252 }
253 }
254}