123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- using System.Collections.Generic;
- using System.Linq;
- using UnityEngine;
- using UnityEngine.Playables;
- using UnityEngine.Timeline;
- namespace UnityEditor.Timeline
- {
- class SequenceHierarchy : ScriptableObject
- {
- readonly List<ISequenceState> m_Sequences = new List<ISequenceState>();
- WindowState m_WindowState;
- [SerializeField]
- SequencePath m_SerializedPath;
- public ISequenceState masterSequence
- {
- get { return m_Sequences.FirstOrDefault(); }
- }
- public ISequenceState editSequence
- {
- get { return m_Sequences.LastOrDefault(); }
- }
- public int count
- {
- get { return m_Sequences.Count; }
- }
- public IEnumerable<ISequenceState> allSequences
- {
- get { return m_Sequences; }
- }
- public static SequenceHierarchy CreateInstance()
- {
- var hierarchy = ScriptableObject.CreateInstance<SequenceHierarchy>();
- hierarchy.hideFlags = HideFlags.HideAndDontSave;
- return hierarchy;
- }
- public void Init(WindowState owner)
- {
- m_WindowState = owner;
- }
- // This is called when performing Undo operations.
- // It needs to be called here since some operations are not
- // allowed (EditorUtility.InstanceIDToObject, for example)
- // during the ISerializationCallbackReceiver methods.
- void OnValidate()
- {
- if (m_SerializedPath == null || m_WindowState == null || m_WindowState.GetWindow() == null)
- return;
- m_WindowState.SetCurrentSequencePath(m_SerializedPath, true);
- }
- public void Add(TimelineAsset asset, PlayableDirector director, TimelineClip hostClip)
- {
- if (hostClip == null)
- AddToCurrentUndoGroup(this); // Merge with selection undo
- else
- TimelineUndo.PushUndo(this, "Edit Sub-Timeline");
- Add_Internal(asset, director, hostClip);
- UpdateSerializedPath();
- }
- public void Remove()
- {
- if (m_Sequences.Count == 0) return;
- TimelineUndo.PushUndo(this, "Go to Sub-Timeline");
- Remove_Internal();
- UpdateSerializedPath();
- }
- public ISequenceState GetStateAtIndex(int index)
- {
- return m_Sequences[index];
- }
- public void RemoveUntilCount(int expectedCount)
- {
- if (expectedCount < 0 || m_Sequences.Count <= expectedCount) return;
- TimelineUndo.PushUndo(this, "Go to Sub-Timeline");
- RemoveUntilCount_Internal(expectedCount);
- UpdateSerializedPath();
- }
- public void Clear()
- {
- if (m_Sequences.Count == 0) return;
- AddToCurrentUndoGroup(this);
- Clear_Internal();
- UpdateSerializedPath();
- }
- public SequencePath ToSequencePath()
- {
- var path = new SequencePath();
- if (m_Sequences.Count == 0)
- return path;
- var rootSequence = m_Sequences[0];
- var root = 0;
- if (rootSequence.director != null && rootSequence.director.gameObject != null)
- root = rootSequence.director.gameObject.GetInstanceID();
- else if (rootSequence.asset != null)
- root = rootSequence.asset.GetInstanceID();
- path.SetSelectionRoot(root);
- var resolver = rootSequence.director;
- if (m_Sequences.Count > 1)
- {
- for (int i = 1, n = m_Sequences.Count; i < n; ++i)
- {
- path.AddSubSequence(m_Sequences[i], resolver);
- resolver = m_Sequences[i].director;
- }
- }
- return path;
- }
- public bool NeedsUpdate(SequencePath path, bool forceRebuild)
- {
- return forceRebuild || !SequencePath.AreEqual(m_SerializedPath, path);
- }
- public void FromSequencePath(SequencePath path, bool forceRebuild)
- {
- if (!NeedsUpdate(path, forceRebuild))
- return;
- Clear_Internal();
- var rootObject = EditorUtility.InstanceIDToObject(path.selectionRoot);
- if (rootObject == null)
- {
- UpdateSerializedPath();
- return;
- }
- var candidateAsset = rootObject as TimelineAsset;
- if (candidateAsset != null)
- {
- Add_Internal(candidateAsset, null, null);
- UpdateSerializedPath();
- return;
- }
- var candidateGameObject = rootObject as GameObject;
- if (candidateGameObject == null)
- {
- UpdateSerializedPath();
- return;
- }
- var director = TimelineUtility.GetDirectorComponentForGameObject(candidateGameObject);
- var asset = TimelineUtility.GetTimelineAssetForDirectorComponent(director);
- Add_Internal(asset, director, null);
- if (!path.subElements.Any())
- {
- UpdateSerializedPath();
- return;
- }
- List<SequenceBuildingBlock> buildingBlocks;
- if (ValidateSubElements(path.subElements, director, out buildingBlocks))
- {
- foreach (var buildingBlock in buildingBlocks)
- Add_Internal(buildingBlock.asset, buildingBlock.director, buildingBlock.hostClip);
- }
- UpdateSerializedPath();
- }
- void Add_Internal(TimelineAsset asset, PlayableDirector director, TimelineClip hostClip)
- {
- if (hostClip == null)
- Clear_Internal();
- var parent = m_Sequences.Count > 0 ? editSequence : null;
- m_Sequences.Add(new SequenceState(m_WindowState, asset, director, hostClip, (SequenceState)parent));
- }
- void Remove_Internal()
- {
- m_Sequences.Last().Dispose();
- m_Sequences.RemoveAt(m_Sequences.Count - 1);
- }
- void RemoveUntilCount_Internal(int expectedCount)
- {
- while (m_Sequences.Count > expectedCount)
- {
- Remove_Internal();
- }
- }
- void Clear_Internal()
- {
- RemoveUntilCount_Internal(0);
- }
- void UpdateSerializedPath()
- {
- m_SerializedPath = ToSequencePath();
- }
- static bool ValidateSubElements(List<SequencePathSubElement> subElements, PlayableDirector director, out List<SequenceBuildingBlock> buildingBlocks)
- {
- buildingBlocks = new List<SequenceBuildingBlock>(subElements.Count);
- var currentDirector = director;
- foreach (var element in subElements)
- {
- var timeline = currentDirector.playableAsset as TimelineAsset;
- if (timeline == null)
- return false;
- if (timeline.trackObjects == null)
- return false;
- var track = timeline.GetOutputTracks().FirstOrDefault(t => t.GetInstanceID() == element.trackInstanceID);
- if (track == null)
- return false;
- if (track.Hash() != element.trackHash)
- return false;
- if (track.clips == null)
- return false;
- if (track.clips.Length <= element.clipIndex)
- return false;
- var clip = track.clips[element.clipIndex];
- if (clip == null)
- return false;
- if (clip.Hash() != element.clipHash)
- return false;
- var candidateDirectors = TimelineUtility.GetSubTimelines(clip, director);
- if (element.subDirectorIndex < 0 || element.subDirectorIndex >= candidateDirectors.Count)
- return false;
- var candidateDirector = candidateDirectors[element.subDirectorIndex];
- if (candidateDirector == null || !(candidateDirector.playableAsset is TimelineAsset))
- return false;
- currentDirector = candidateDirector;
- buildingBlocks.Add(
- new SequenceBuildingBlock
- {
- asset = currentDirector.playableAsset as TimelineAsset,
- director = currentDirector,
- hostClip = clip
- });
- }
- return true;
- }
- struct SequenceBuildingBlock
- {
- public TimelineAsset asset;
- public PlayableDirector director;
- public TimelineClip hostClip;
- }
- static void AddToCurrentUndoGroup(Object target)
- {
- if (target == null) return;
- var group = Undo.GetCurrentGroup();
- var groupName = Undo.GetCurrentGroupName();
- EditorUtility.SetDirty(target);
- Undo.RegisterCompleteObjectUndo(target, groupName);
- Undo.CollapseUndoOperations(group);
- }
- }
- }
|