Unity-jump-proj
This commit is contained in:
@ -0,0 +1,302 @@
|
||||
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;
|
||||
|
||||
bool hasDifferentRoot = m_WindowState.GetCurrentSequencePath().selectionRoot != m_SerializedPath.selectionRoot;
|
||||
if (m_WindowState.GetWindow().locked && hasDifferentRoot)
|
||||
return;
|
||||
|
||||
EditorApplication.delayCall += () => { 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, L10n.Tr("Edit Sub-Timeline"));
|
||||
|
||||
Add_Internal(asset, director, hostClip);
|
||||
|
||||
UpdateSerializedPath();
|
||||
}
|
||||
|
||||
public void Remove()
|
||||
{
|
||||
if (m_Sequences.Count == 0) return;
|
||||
|
||||
TimelineUndo.PushUndo(this, L10n.Tr("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, L10n.Tr("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);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user