diff options
Diffstat (limited to 'Library/PackageCache/com.unity.timeline@1.2.13/Runtime')
156 files changed, 11029 insertions, 0 deletions
diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Activation.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Activation.meta new file mode 100644 index 0000000..ed3ac63 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Activation.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d0cd29fb1ad218b48b814bc3e6d8ac0e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Activation/ActivationMixerPlayable.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Activation/ActivationMixerPlayable.cs new file mode 100644 index 0000000..61054f7 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Activation/ActivationMixerPlayable.cs @@ -0,0 +1,71 @@ +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + class ActivationMixerPlayable : PlayableBehaviour + { + ActivationTrack.PostPlaybackState m_PostPlaybackState; + bool m_BoundGameObjectInitialStateIsActive; + + private GameObject m_BoundGameObject; + + + public static ScriptPlayable<ActivationMixerPlayable> Create(PlayableGraph graph, int inputCount) + { + return ScriptPlayable<ActivationMixerPlayable>.Create(graph, inputCount); + } + + public ActivationTrack.PostPlaybackState postPlaybackState + { + get { return m_PostPlaybackState; } + set { m_PostPlaybackState = value; } + } + + public override void OnPlayableDestroy(Playable playable) + { + if (m_BoundGameObject == null) + return; + + switch (m_PostPlaybackState) + { + case ActivationTrack.PostPlaybackState.Active: + m_BoundGameObject.SetActive(true); + break; + case ActivationTrack.PostPlaybackState.Inactive: + m_BoundGameObject.SetActive(false); + break; + case ActivationTrack.PostPlaybackState.Revert: + m_BoundGameObject.SetActive(m_BoundGameObjectInitialStateIsActive); + break; + case ActivationTrack.PostPlaybackState.LeaveAsIs: + default: + break; + } + } + + public override void ProcessFrame(Playable playable, FrameData info, object playerData) + { + if (m_BoundGameObject == null) + { + m_BoundGameObject = playerData as GameObject; + m_BoundGameObjectInitialStateIsActive = m_BoundGameObject != null && m_BoundGameObject.activeSelf; + } + + if (m_BoundGameObject == null) + return; + + int inputCount = playable.GetInputCount(); + bool hasInput = false; + for (int i = 0; i < inputCount; i++) + { + if (playable.GetInputWeight(i) > 0) + { + hasInput = true; + break; + } + } + + m_BoundGameObject.SetActive(hasInput); + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Activation/ActivationMixerPlayable.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Activation/ActivationMixerPlayable.cs.meta new file mode 100644 index 0000000..7ce2073 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Activation/ActivationMixerPlayable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e165a99d845c10e4ea0f546e542e8684 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Activation/ActivationPlayableAsset.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Activation/ActivationPlayableAsset.cs new file mode 100644 index 0000000..7304741 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Activation/ActivationPlayableAsset.cs @@ -0,0 +1,29 @@ +#if UNITY_EDITOR +using System.ComponentModel; +#endif +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// Playable Asset class for Activation Tracks + /// </summary> +#if UNITY_EDITOR + [DisplayName("Activation Clip")] +#endif + class ActivationPlayableAsset : PlayableAsset, ITimelineClipAsset + { + /// <summary> + /// Returns a description of the features supported by activation clips + /// </summary> + public ClipCaps clipCaps { get { return ClipCaps.None; } } + + /// <summary> + /// Overrides PlayableAsset.CreatePlayable() to inject needed Playables for an activation asset + /// </summary> + public override Playable CreatePlayable(PlayableGraph graph, GameObject go) + { + return Playable.Create(graph); + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Activation/ActivationPlayableAsset.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Activation/ActivationPlayableAsset.cs.meta new file mode 100644 index 0000000..e22155a --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Activation/ActivationPlayableAsset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fde0d25a170598d46a0b9dc16b4527a5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Activation/ActivationTrack.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Activation/ActivationTrack.cs new file mode 100644 index 0000000..8e06ddb --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Activation/ActivationTrack.cs @@ -0,0 +1,93 @@ +using System; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// Track that can be used to control the active state of a GameObject. + /// </summary> + [Serializable] + [TrackClipType(typeof(ActivationPlayableAsset))] + [TrackBindingType(typeof(GameObject))] + [ExcludeFromPreset] + public class ActivationTrack : TrackAsset + { + [SerializeField] + PostPlaybackState m_PostPlaybackState = PostPlaybackState.LeaveAsIs; + ActivationMixerPlayable m_ActivationMixer; + + /// <summary> + /// Specify what state to leave the GameObject in after the Timeline has finished playing. + /// </summary> + public enum PostPlaybackState + { + /// <summary> + /// Set the GameObject to active. + /// </summary> + Active, + + /// <summary> + /// Set the GameObject to Inactive. + /// </summary> + Inactive, + + /// <summary> + /// Revert the GameObject to the state in was in before the Timeline was playing. + /// </summary> + Revert, + + /// <summary> + /// Leave the GameObject in the state it was when the Timeline was stopped. + /// </summary> + LeaveAsIs + } + + internal override bool CanCompileClips() + { + return !hasClips || base.CanCompileClips(); + } + + /// <summary> + /// Specifies what state to leave the GameObject in after the Timeline has finished playing. + /// </summary> + public PostPlaybackState postPlaybackState + { + get { return m_PostPlaybackState; } + set { m_PostPlaybackState = value; UpdateTrackMode(); } + } + + /// <inheritdoc/> + public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount) + { + var mixer = ActivationMixerPlayable.Create(graph, inputCount); + m_ActivationMixer = mixer.GetBehaviour(); + + UpdateTrackMode(); + + return mixer; + } + + internal void UpdateTrackMode() + { + if (m_ActivationMixer != null) + m_ActivationMixer.postPlaybackState = m_PostPlaybackState; + } + + /// <inheritdoc/> + public override void GatherProperties(PlayableDirector director, IPropertyCollector driver) + { + var gameObject = GetGameObjectBinding(director); + if (gameObject != null) + { + driver.AddFromName(gameObject, "m_IsActive"); + } + } + + /// <inheritdoc/> + protected override void OnCreateClip(TimelineClip clip) + { + clip.displayName = "Active"; + base.OnCreateClip(clip); + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Activation/ActivationTrack.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Activation/ActivationTrack.cs.meta new file mode 100644 index 0000000..82ab218 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Activation/ActivationTrack.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 21bf7f712d84d26478ebe6a299f21738 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation.meta new file mode 100644 index 0000000..7fa19e2 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: de9eb5e2046ffc9448f07e495c436506 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/AnimationOutputWeightProcessor.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/AnimationOutputWeightProcessor.cs new file mode 100644 index 0000000..ae190e3 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/AnimationOutputWeightProcessor.cs @@ -0,0 +1,93 @@ +using System.Collections.Generic; +using UnityEngine.Animations; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + // Does a post processing of the weights on an animation track to properly normalize + // the mixer weights so that blending does not bring default poses and subtracks, layers and + // layer graphs blend correctly + class AnimationOutputWeightProcessor : ITimelineEvaluateCallback + { + struct WeightInfo + { + public Playable mixer; + public Playable parentMixer; + public int port; + } + + AnimationPlayableOutput m_Output; + AnimationMotionXToDeltaPlayable m_MotionXPlayable; + readonly List<WeightInfo> m_Mixers = new List<WeightInfo>(); + + public AnimationOutputWeightProcessor(AnimationPlayableOutput output) + { + m_Output = output; + output.SetWeight(0); + FindMixers(); + } + + void FindMixers() + { + var playable = m_Output.GetSourcePlayable(); + var outputPort = m_Output.GetSourceOutputPort(); + + m_Mixers.Clear(); + // only write the final output in playmode. it should always be 1 in editor because we blend to the defaults + FindMixers(playable, outputPort, playable.GetInput(outputPort)); + } + + // Recursively accumulates mixers. + void FindMixers(Playable parent, int port, Playable node) + { + if (!node.IsValid()) + return; + + var type = node.GetPlayableType(); + if (type == typeof(AnimationMixerPlayable) || type == typeof(AnimationLayerMixerPlayable)) + { + // use post fix traversal so children come before parents + int subCount = node.GetInputCount(); + for (int j = 0; j < subCount; j++) + { + FindMixers(node, j, node.GetInput(j)); + } + + // if we encounter a layer mixer, we assume there is nesting occuring + // and we modulate the weight instead of overwriting it. + var weightInfo = new WeightInfo + { + parentMixer = parent, + mixer = node, + port = port, + }; + m_Mixers.Add(weightInfo); + } + else + { + var count = node.GetInputCount(); + for (var i = 0; i < count; i++) + { + FindMixers(parent, port, node.GetInput(i)); + } + } + } + + public void Evaluate() + { + float weight = 1; + m_Output.SetWeight(1); + for (int i = 0; i < m_Mixers.Count; i++) + { + var mixInfo = m_Mixers[i]; + weight = WeightUtility.NormalizeMixer(mixInfo.mixer); + mixInfo.parentMixer.SetInputWeight(mixInfo.port, weight); + } + + // only write the final weight in player/playmode. In editor, we are blending to the appropriate defaults + // the last mixer in the list is the final blend, since the list is composed post-order. + if (Application.isPlaying) + m_Output.SetWeight(weight); + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/AnimationOutputWeightProcessor.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/AnimationOutputWeightProcessor.cs.meta new file mode 100644 index 0000000..c487e39 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/AnimationOutputWeightProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a429b38ee9d48c7408c8870baf406034 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/AnimationPlayableAsset.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/AnimationPlayableAsset.cs new file mode 100644 index 0000000..68355c0 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/AnimationPlayableAsset.cs @@ -0,0 +1,326 @@ +using System.Collections.Generic; +using UnityEngine.Animations; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// A Playable Asset that represents a single AnimationClip clip. + /// </summary> + [System.Serializable, NotKeyable] + public partial class AnimationPlayableAsset : PlayableAsset, ITimelineClipAsset, IPropertyPreview + { + /// <summary> + /// Whether the source AnimationClip loops during playback. + /// </summary> + public enum LoopMode + { + /// <summary> + /// Use the loop time setting from the source AnimationClip. + /// </summary> + [Tooltip("Use the loop time setting from the source AnimationClip.")] + UseSourceAsset = 0, + + /// <summary> + /// The source AnimationClip loops during playback. + /// </summary> + [Tooltip("The source AnimationClip loops during playback.")] + On = 1, + + /// <summary> + /// The source AnimationClip does not loop during playback. + /// </summary> + [Tooltip("The source AnimationClip does not loop during playback.")] + Off = 2 + } + + + [SerializeField] private AnimationClip m_Clip; + [SerializeField] private Vector3 m_Position = Vector3.zero; + [SerializeField] private Vector3 m_EulerAngles = Vector3.zero; + [SerializeField] private bool m_UseTrackMatchFields = true; + [SerializeField] private MatchTargetFields m_MatchTargetFields = MatchTargetFieldConstants.All; + [SerializeField] private bool m_RemoveStartOffset = true; // set by animation track prior to compilation + [SerializeField] private bool m_ApplyFootIK = true; + [SerializeField] private LoopMode m_Loop = LoopMode.UseSourceAsset; + + +#if UNITY_EDITOR + private AnimationOffsetPlayable m_AnimationOffsetPlayable; +#endif + + /// <summary> + /// The translational offset of the clip + /// </summary> + public Vector3 position + { + get + { + return m_Position; + } + set + { + m_Position = value; +#if UNITY_EDITOR + if (m_AnimationOffsetPlayable.IsValid()) + m_AnimationOffsetPlayable.SetPosition(position); +#endif + } + } + + /// <summary> + /// The rotational offset of the clip, expressed as a Quaternion + /// </summary> + public Quaternion rotation + { + get + { + return Quaternion.Euler(m_EulerAngles); + } + + set + { + m_EulerAngles = value.eulerAngles; +#if UNITY_EDITOR + if (m_AnimationOffsetPlayable.IsValid()) + m_AnimationOffsetPlayable.SetRotation(value); +#endif + } + } + + /// <summary> + /// The rotational offset of the clip, expressed in Euler angles + /// </summary> + public Vector3 eulerAngles + { + get { return m_EulerAngles; } + set + { + m_EulerAngles = value; +#if UNITY_EDITOR + if (m_AnimationOffsetPlayable.IsValid()) + m_AnimationOffsetPlayable.SetRotation(rotation); +#endif + } + } + + /// <summary> + /// Specifies whether to use offset matching options as defined by the track. + /// </summary> + public bool useTrackMatchFields + { + get { return m_UseTrackMatchFields; } + set { m_UseTrackMatchFields = value; } + } + + /// <summary> + /// Specifies which fields should be matched when aligning offsets. + /// </summary> + public MatchTargetFields matchTargetFields + { + get { return m_MatchTargetFields; } + set { m_MatchTargetFields = value; } + } + + /// <summary> + /// Whether to make the animation clip play relative to its first keyframe. + /// </summary> + /// <remarks> + /// This option only applies to animation clips that animate Transform components. + /// </remarks> + public bool removeStartOffset + { + get { return m_RemoveStartOffset; } + set { m_RemoveStartOffset = value; } + } + + + /// <summary> + /// Enable to apply foot IK to the AnimationClip when the target is humanoid. + /// </summary> + public bool applyFootIK + { + get { return m_ApplyFootIK; } + set { m_ApplyFootIK = value; } + } + + /// <summary> + /// Whether the source AnimationClip loops during playback + /// </summary> + public LoopMode loop + { + get { return m_Loop; } + set { m_Loop = value; } + } + + + internal bool hasRootTransforms + { + get { return m_Clip != null && HasRootTransforms(m_Clip); } + } + + // used for legacy 'scene' mode. + internal AppliedOffsetMode appliedOffsetMode { get; set; } + + + /// <summary> + /// The source animation clip + /// </summary> + public AnimationClip clip + { + get { return m_Clip; } + set + { + if (value != null) + name = "AnimationPlayableAsset of " + value.name; + m_Clip = value; + } + } + + /// <summary> + /// Returns the duration required to play the animation clip exactly once + /// </summary> + public override double duration + { + get + { + double length = TimeUtility.GetAnimationClipLength(clip); + if (length < float.Epsilon) + return base.duration; + return length; + } + } + + /// <summary> + /// Returns a description of the PlayableOutputs that may be created for this asset. + /// </summary> + public override IEnumerable<PlayableBinding> outputs + { + get { yield return AnimationPlayableBinding.Create(name, this); } + } + + /// <summary> + /// Creates the root of a Playable subgraph to play the animation clip. + /// </summary> + /// <param name="graph">PlayableGraph that will own the playable</param> + /// <param name="go">The gameobject that triggered the graph build</param> + /// <returns>The root playable of the subgraph</returns> + public override Playable CreatePlayable(PlayableGraph graph, GameObject go) + { + Playable root = CreatePlayable(graph, m_Clip, position, eulerAngles, removeStartOffset, appliedOffsetMode, applyFootIK, m_Loop); + +#if UNITY_EDITOR + m_AnimationOffsetPlayable = AnimationOffsetPlayable.Null; + if (root.IsValid() && root.IsPlayableOfType<AnimationOffsetPlayable>()) + { + m_AnimationOffsetPlayable = (AnimationOffsetPlayable)root; + } + + LiveLink(); +#endif + + return root; + } + + internal static Playable CreatePlayable(PlayableGraph graph, AnimationClip clip, Vector3 positionOffset, Vector3 eulerOffset, bool removeStartOffset, AppliedOffsetMode mode, bool applyFootIK, LoopMode loop) + { + if (clip == null || clip.legacy) + return Playable.Null; + + + var clipPlayable = AnimationClipPlayable.Create(graph, clip); + clipPlayable.SetRemoveStartOffset(removeStartOffset); + clipPlayable.SetApplyFootIK(applyFootIK); + clipPlayable.SetOverrideLoopTime(loop != LoopMode.UseSourceAsset); + clipPlayable.SetLoopTime(loop == LoopMode.On); + + Playable root = clipPlayable; + + if (ShouldApplyScaleRemove(mode)) + { + var removeScale = AnimationRemoveScalePlayable.Create(graph, 1); + graph.Connect(root, 0, removeScale, 0); + removeScale.SetInputWeight(0, 1.0f); + root = removeScale; + } + + if (ShouldApplyOffset(mode, clip)) + { + var offsetPlayable = AnimationOffsetPlayable.Create(graph, positionOffset, Quaternion.Euler(eulerOffset), 1); + graph.Connect(root, 0, offsetPlayable, 0); + offsetPlayable.SetInputWeight(0, 1.0F); + root = offsetPlayable; + } + + return root; + } + + private static bool ShouldApplyOffset(AppliedOffsetMode mode, AnimationClip clip) + { + if (mode == AppliedOffsetMode.NoRootTransform || mode == AppliedOffsetMode.SceneOffsetLegacy) + return false; + + return HasRootTransforms(clip); + } + + private static bool ShouldApplyScaleRemove(AppliedOffsetMode mode) + { + return mode == AppliedOffsetMode.SceneOffsetLegacyEditor || mode == AppliedOffsetMode.SceneOffsetLegacy || mode == AppliedOffsetMode.TransformOffsetLegacy; + } + +#if UNITY_EDITOR + public void LiveLink() + { + if (m_AnimationOffsetPlayable.IsValid()) + { + m_AnimationOffsetPlayable.SetPosition(position); + m_AnimationOffsetPlayable.SetRotation(rotation); + } + } + +#endif + + /// <summary> + /// Returns the capabilities of TimelineClips that contain a AnimationPlayableAsset + /// </summary> + public ClipCaps clipCaps + { + get + { + var caps = ClipCaps.All; + if (m_Clip == null || (m_Loop == LoopMode.Off) || (m_Loop == LoopMode.UseSourceAsset && !m_Clip.isLooping)) + caps &= ~ClipCaps.Looping; + + // empty clips don't support clip in. This allows trim operations to simply become + // move operations + if (m_Clip == null || m_Clip.empty) + caps &= ~ClipCaps.ClipIn; + + return caps; + } + } + + /// <summary> + /// Resets the offsets to default values + /// </summary> + public void ResetOffsets() + { + position = Vector3.zero; + eulerAngles = Vector3.zero; + } + + /// <inheritdoc/> + public void GatherProperties(PlayableDirector director, IPropertyCollector driver) + { + driver.AddFromClip(m_Clip); + } + + internal static bool HasRootTransforms(AnimationClip clip) + { + if (clip == null || clip.empty) + return false; + + return clip.hasRootMotion || clip.hasGenericRootTransform || clip.hasMotionCurves || clip.hasRootCurves; + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/AnimationPlayableAsset.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/AnimationPlayableAsset.cs.meta new file mode 100644 index 0000000..698bcd5 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/AnimationPlayableAsset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 030f85c3f73729f4f976f66ffb23b875 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/AnimationPreviewUpdateCallback.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/AnimationPreviewUpdateCallback.cs new file mode 100644 index 0000000..560f900 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/AnimationPreviewUpdateCallback.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; +using UnityEngine.Animations; +using UnityEngine.Experimental.Animations; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + class AnimationPreviewUpdateCallback : ITimelineEvaluateCallback + { + AnimationPlayableOutput m_Output; + PlayableGraph m_Graph; + List<IAnimationWindowPreview> m_PreviewComponents; + + public AnimationPreviewUpdateCallback(AnimationPlayableOutput output) + { + m_Output = output; + + Playable playable = m_Output.GetSourcePlayable(); + if (playable.IsValid()) + { + m_Graph = playable.GetGraph(); + } + } + + public void Evaluate() + { + if (!m_Graph.IsValid()) + return; + + if (m_PreviewComponents == null) + FetchPreviewComponents(); + + foreach (var component in m_PreviewComponents) + { + if (component != null) + { + component.UpdatePreviewGraph(m_Graph); + } + } + } + + private void FetchPreviewComponents() + { + m_PreviewComponents = new List<IAnimationWindowPreview>(); + + var animator = m_Output.GetTarget(); + if (animator == null) + return; + + var gameObject = animator.gameObject; + m_PreviewComponents.AddRange(gameObject.GetComponents<IAnimationWindowPreview>()); + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/AnimationPreviewUpdateCallback.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/AnimationPreviewUpdateCallback.cs.meta new file mode 100644 index 0000000..9d6167b --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/AnimationPreviewUpdateCallback.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 755e3e942f7784d458bddba421c0bb72 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/AnimationTrack.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/AnimationTrack.cs new file mode 100644 index 0000000..21e811d --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/AnimationTrack.cs @@ -0,0 +1,971 @@ +using System; +using System.Collections.Generic; +using UnityEngine.Animations; +using UnityEngine.Experimental.Animations; +using UnityEngine.Playables; +using UnityEngine.Serialization; + +#if UNITY_EDITOR +using UnityEditor; +#endif + +namespace UnityEngine.Timeline +{ + /// <summary> + /// Flags specifying which offset fields to match + /// </summary> + [Flags] + public enum MatchTargetFields + { + /// <summary> + /// Translation X value + /// </summary> + PositionX = 1 << 0, + /// <summary> + /// Translation Y value + /// </summary> + PositionY = 1 << 1, + /// <summary> + /// Translation Z value + /// </summary> + PositionZ = 1 << 2, + /// <summary> + /// Rotation Euler Angle X value + /// </summary> + RotationX = 1 << 3, + /// <summary> + /// Rotation Euler Angle Y value + /// </summary> + RotationY = 1 << 4, + /// <summary> + /// Rotation Euler Angle Z value + /// </summary> + RotationZ = 1 << 5 + } + + /// <summary> + /// Describes what is used to set the starting position and orientation of each Animation Track. + /// </summary> + /// <remarks> + /// By default, each Animation Track uses ApplyTransformOffsets to start from a set position and orientation. + /// To offset each Animation Track based on the current position and orientation in the scene, use ApplySceneOffsets. + /// </remarks> + public enum TrackOffset + { + /// <summary> + /// Use this setting to offset each Animation Track based on a set position and orientation. + /// </summary> + ApplyTransformOffsets, + /// <summary> + /// Use this setting to offset each Animation Track based on the current position and orientation in the scene. + /// </summary> + ApplySceneOffsets, + /// <summary> + /// Use this setting to offset root transforms based on the state of the animator. + /// </summary> + /// <remarks> + /// Only use this setting to support legacy Animation Tracks. This mode may be deprecated in a future release. + /// + /// In Auto mode, when the animator bound to the animation track contains an AnimatorController, it offsets all animations similar to ApplySceneOffsets. + /// If no controller is assigned, then all offsets are set to start from a fixed position and orientation, similar to ApplyTransformOffsets. + /// In Auto mode, in most cases, root transforms are not affected by local scale or Animator.humanScale, unless the animator has an AnimatorController and Animator.applyRootMotion is set to true. + /// </remarks> + Auto + } + + + // offset mode + enum AppliedOffsetMode + { + NoRootTransform, + TransformOffset, + SceneOffset, + TransformOffsetLegacy, + SceneOffsetLegacy, + SceneOffsetEditor, // scene offset mode in editor + SceneOffsetLegacyEditor, + } + + + // separate from the enum to hide them from UI elements + static class MatchTargetFieldConstants + { + public static MatchTargetFields All = MatchTargetFields.PositionX | MatchTargetFields.PositionY | + MatchTargetFields.PositionZ | MatchTargetFields.RotationX | + MatchTargetFields.RotationY | MatchTargetFields.RotationZ; + + public static MatchTargetFields None = 0; + + public static MatchTargetFields Position = MatchTargetFields.PositionX | MatchTargetFields.PositionY | + MatchTargetFields.PositionZ; + + public static MatchTargetFields Rotation = MatchTargetFields.RotationX | MatchTargetFields.RotationY | + MatchTargetFields.RotationZ; + + public static bool HasAny(this MatchTargetFields me, MatchTargetFields fields) + { + return (me & fields) != None; + } + + public static MatchTargetFields Toggle(this MatchTargetFields me, MatchTargetFields flag) + { + return me ^ flag; + } + } + + + /// <summary> + /// A Timeline track used for playing back animations on an Animator. + /// </summary> + [Serializable] + [TrackClipType(typeof(AnimationPlayableAsset), false)] + [TrackBindingType(typeof(Animator))] + [ExcludeFromPreset] + public partial class AnimationTrack : TrackAsset, ILayerable + { + const string k_DefaultInfiniteClipName = "Recorded"; + const string k_DefaultRecordableClipName = "Recorded"; + + [SerializeField, FormerlySerializedAs("m_OpenClipPreExtrapolation")] + TimelineClip.ClipExtrapolation m_InfiniteClipPreExtrapolation = TimelineClip.ClipExtrapolation.None; + + [SerializeField, FormerlySerializedAs("m_OpenClipPostExtrapolation")] + TimelineClip.ClipExtrapolation m_InfiniteClipPostExtrapolation = TimelineClip.ClipExtrapolation.None; + + [SerializeField, FormerlySerializedAs("m_OpenClipOffsetPosition")] + Vector3 m_InfiniteClipOffsetPosition = Vector3.zero; + + [SerializeField, FormerlySerializedAs("m_OpenClipOffsetEulerAngles")] + Vector3 m_InfiniteClipOffsetEulerAngles = Vector3.zero; + + [SerializeField, FormerlySerializedAs("m_OpenClipTimeOffset")] + double m_InfiniteClipTimeOffset; + + [SerializeField, FormerlySerializedAs("m_OpenClipRemoveOffset")] + bool m_InfiniteClipRemoveOffset; // cached value for remove offset + + [SerializeField] + bool m_InfiniteClipApplyFootIK = true; + + [SerializeField, HideInInspector] + AnimationPlayableAsset.LoopMode mInfiniteClipLoop = AnimationPlayableAsset.LoopMode.UseSourceAsset; + + [SerializeField] + MatchTargetFields m_MatchTargetFields = MatchTargetFieldConstants.All; + [SerializeField] + Vector3 m_Position = Vector3.zero; + [SerializeField] + Vector3 m_EulerAngles = Vector3.zero; + + + [SerializeField] AvatarMask m_AvatarMask; + [SerializeField] bool m_ApplyAvatarMask = true; + + [SerializeField] TrackOffset m_TrackOffset = TrackOffset.ApplyTransformOffsets; + + [SerializeField, HideInInspector] AnimationClip m_InfiniteClip; + + +#if UNITY_EDITOR + private AnimationClip m_DefaultPoseClip; + private AnimationClip m_CachedPropertiesClip; + + AnimationOffsetPlayable m_ClipOffset; + + private Vector3 m_SceneOffsetPosition = Vector3.zero; + private Vector3 m_SceneOffsetRotation = Vector3.zero; + + private bool m_HasPreviewComponents = false; +#endif + + /// <summary> + /// The translation offset of the entire track. + /// </summary> + public Vector3 position + { + get { return m_Position; } + set { m_Position = value; } + } + + /// <summary> + /// The rotation offset of the entire track, expressed as a quaternion. + /// </summary> + public Quaternion rotation + { + get { return Quaternion.Euler(m_EulerAngles); } + set { m_EulerAngles = value.eulerAngles; } + } + + /// <summary> + /// The euler angle representation of the rotation offset of the entire track. + /// </summary> + public Vector3 eulerAngles + { + get { return m_EulerAngles; } + set { m_EulerAngles = value; } + } + + /// <summary> + /// Specifies whether to apply track offsets to all clips on the track. + /// </summary> + /// <remarks> + /// This can be used to offset all clips on a track, in addition to the clips individual offsets. + /// </remarks> + [Obsolete("applyOffset is deprecated. Use trackOffset instead", true)] + public bool applyOffsets + { + get { return false; } + set {} + } + + /// <summary> + /// Specifies what is used to set the starting position and orientation of an Animation Track. + /// </summary> + /// <remarks> + /// Track Offset is only applied when the Animation Track contains animation that modifies the root Transform. + /// </remarks> + public TrackOffset trackOffset + { + get { return m_TrackOffset; } + set { m_TrackOffset = value; } + } + + /// <summary> + /// Specifies which fields to match when aligning offsets of clips. + /// </summary> + public MatchTargetFields matchTargetFields + { + get { return m_MatchTargetFields; } + set { m_MatchTargetFields = value & MatchTargetFieldConstants.All; } + } + + /// <summary> + /// An AnimationClip storing the data for an infinite track. + /// </summary> + /// <remarks> + /// The value of this property is null when the AnimationTrack is in Clip Mode. + /// </remarks> + public AnimationClip infiniteClip + { + get { return m_InfiniteClip; } + internal set { m_InfiniteClip = value; } + } + + // saved value for converting to/from infinite mode + internal bool infiniteClipRemoveOffset + { + get { return m_InfiniteClipRemoveOffset; } + set { m_InfiniteClipRemoveOffset = value; } + } + + /// <summary> + /// Specifies the AvatarMask to be applied to all clips on the track. + /// </summary> + /// <remarks> + /// Applying an AvatarMask to an animation track will allow discarding portions of the animation being applied on the track. + /// </remarks> + public AvatarMask avatarMask + { + get { return m_AvatarMask; } + set { m_AvatarMask = value; } + } + + /// <summary> + /// Specifies whether to apply the AvatarMask to the track. + /// </summary> + public bool applyAvatarMask + { + get { return m_ApplyAvatarMask; } + set { m_ApplyAvatarMask = value; } + } + + // is this track compilable + + internal override bool CanCompileClips() + { + return !muted && (m_Clips.Count > 0 || (m_InfiniteClip != null && !m_InfiniteClip.empty)); + } + + /// <inheritdoc/> + public override IEnumerable<PlayableBinding> outputs + { + get { yield return AnimationPlayableBinding.Create(name, this); } + } + + + /// <summary> + /// Specifies whether the Animation Track has clips, or is in infinite mode. + /// </summary> + public bool inClipMode + { + get { return clips != null && clips.Length != 0; } + } + + /// <summary> + /// The translation offset of a track in infinite mode. + /// </summary> + public Vector3 infiniteClipOffsetPosition + { + get { return m_InfiniteClipOffsetPosition; } + set { m_InfiniteClipOffsetPosition = value; } + } + + /// <summary> + /// The rotation offset of a track in infinite mode. + /// </summary> + public Quaternion infiniteClipOffsetRotation + { + get { return Quaternion.Euler(m_InfiniteClipOffsetEulerAngles); } + set { m_InfiniteClipOffsetEulerAngles = value.eulerAngles; } + } + + /// <summary> + /// The euler angle representation of the rotation offset of the track when in infinite mode. + /// </summary> + public Vector3 infiniteClipOffsetEulerAngles + { + get { return m_InfiniteClipOffsetEulerAngles; } + set { m_InfiniteClipOffsetEulerAngles = value; } + } + + internal bool infiniteClipApplyFootIK + { + get { return m_InfiniteClipApplyFootIK; } + set { m_InfiniteClipApplyFootIK = value; } + } + + internal double infiniteClipTimeOffset + { + get { return m_InfiniteClipTimeOffset; } + set { m_InfiniteClipTimeOffset = value; } + } + + /// <summary> + /// The saved state of pre-extrapolation for clips converted to infinite mode. + /// </summary> + public TimelineClip.ClipExtrapolation infiniteClipPreExtrapolation + { + get { return m_InfiniteClipPreExtrapolation; } + set { m_InfiniteClipPreExtrapolation = value; } + } + + /// <summary> + /// The saved state of post-extrapolation for clips when converted to infinite mode. + /// </summary> + public TimelineClip.ClipExtrapolation infiniteClipPostExtrapolation + { + get { return m_InfiniteClipPostExtrapolation; } + set { m_InfiniteClipPostExtrapolation = value; } + } + + /// <summary> + /// The saved state of animation clip loop state when converted to infinite mode + /// </summary> + internal AnimationPlayableAsset.LoopMode infiniteClipLoop + { + get { return mInfiniteClipLoop; } + set { mInfiniteClipLoop = value; } + } + + [ContextMenu("Reset Offsets")] + void ResetOffsets() + { + m_Position = Vector3.zero; + m_EulerAngles = Vector3.zero; + UpdateClipOffsets(); + } + + /// <summary> + /// Creates a TimelineClip on this track that uses an AnimationClip. + /// </summary> + /// <param name="clip">Source animation clip of the resulting TimelineClip.</param> + /// <returns>A new TimelineClip which has an AnimationPlayableAsset asset attached.</returns> + public TimelineClip CreateClip(AnimationClip clip) + { + if (clip == null) + return null; + + var newClip = CreateClip<AnimationPlayableAsset>(); + AssignAnimationClip(newClip, clip); + return newClip; + } + + /// <summary> + /// Creates an AnimationClip that stores the data for an infinite track. + /// </summary> + /// <remarks> + /// If an infiniteClip already exists, this method produces no result, even if you provide a different value + /// for infiniteClipName. + /// </remarks> + /// <remarks> + /// This method can't create an infinite clip for an AnimationTrack that contains one or more Timeline clips. + /// Use AnimationTrack.inClipMode to determine whether it is possible to create an infinite clip on an AnimationTrack. + /// </remarks> + /// <remarks> + /// When used from the editor, this method attempts to save the created infinite clip to the TimelineAsset. + /// The TimelineAsset must already exist in the AssetDatabase to save the infinite clip. If the TimelineAsset + /// does not exist, the infinite clip is still created but it is not saved. + /// </remarks> + /// <param name="infiniteClipName"> + /// The name of the AnimationClip to create. + /// This method does not ensure unique names. If you want a unique clip name, you must provide one. + /// See ObjectNames.GetUniqueName for information on a method that creates unique names. + /// </param> + public void CreateInfiniteClip(string infiniteClipName) + { + if (inClipMode) + { + Debug.LogWarning("CreateInfiniteClip cannot create an infinite clip for an AnimationTrack that contains one or more Timeline Clips."); + return; + } + + if (m_InfiniteClip != null) + return; + + m_InfiniteClip = TimelineCreateUtilities.CreateAnimationClipForTrack(string.IsNullOrEmpty(infiniteClipName) ? k_DefaultInfiniteClipName : infiniteClipName, this, false); + } + + /// <summary> + /// Creates a TimelineClip, AnimationPlayableAsset and an AnimationClip. Use this clip to record in a timeline. + /// </summary> + /// <remarks> + /// When used from the editor, this method attempts to save the created recordable clip to the TimelineAsset. + /// The TimelineAsset must already exist in the AssetDatabase to save the recordable clip. If the TimelineAsset + /// does not exist, the recordable clip is still created but it is not saved. + /// </remarks> + /// <param name="animClipName"> + /// The name of the AnimationClip to create. + /// This method does not ensure unique names. If you want a unique clip name, you must provide one. + /// See ObjectNames.GetUniqueName for information on a method that creates unique names. + /// </param> + /// <returns> + /// Returns a new TimelineClip with an AnimationPlayableAsset asset attached. + /// </returns> + public TimelineClip CreateRecordableClip(string animClipName) + { + var clip = TimelineCreateUtilities.CreateAnimationClipForTrack(string.IsNullOrEmpty(animClipName) ? k_DefaultRecordableClipName : animClipName, this, false); + + var timelineClip = CreateClip(clip); + timelineClip.displayName = animClipName; + timelineClip.recordable = true; + timelineClip.start = 0; + timelineClip.duration = 1; + + var apa = timelineClip.asset as AnimationPlayableAsset; + if (apa != null) + apa.removeStartOffset = false; + + return timelineClip; + } + +#if UNITY_EDITOR + internal Vector3 sceneOffsetPosition + { + get { return m_SceneOffsetPosition; } + set { m_SceneOffsetPosition = value; } + } + + internal Vector3 sceneOffsetRotation + { + get { return m_SceneOffsetRotation; } + set { m_SceneOffsetRotation = value; } + } + + internal bool hasPreviewComponents + { + get + { + if (m_HasPreviewComponents) + return true; + + var parentTrack = parent as AnimationTrack; + if (parentTrack != null) + { + return parentTrack.hasPreviewComponents; + } + + return false; + } + } +#endif + + /// <summary> + /// Used to initialize default values on a newly created clip + /// </summary> + /// <param name="clip">The clip added to the track</param> + protected override void OnCreateClip(TimelineClip clip) + { + var extrapolation = TimelineClip.ClipExtrapolation.None; + if (!isSubTrack) + extrapolation = TimelineClip.ClipExtrapolation.Hold; + clip.preExtrapolationMode = extrapolation; + clip.postExtrapolationMode = extrapolation; + } + + protected internal override int CalculateItemsHash() + { + return GetAnimationClipHash(m_InfiniteClip).CombineHash(base.CalculateItemsHash()); + } + + internal void UpdateClipOffsets() + { +#if UNITY_EDITOR + if (m_ClipOffset.IsValid()) + { + m_ClipOffset.SetPosition(position); + m_ClipOffset.SetRotation(rotation); + } +#endif + } + + Playable CompileTrackPlayable(PlayableGraph graph, TrackAsset track, GameObject go, IntervalTree<RuntimeElement> tree, AppliedOffsetMode mode) + { + var mixer = AnimationMixerPlayable.Create(graph, track.clips.Length); + for (int i = 0; i < track.clips.Length; i++) + { + var c = track.clips[i]; + var asset = c.asset as PlayableAsset; + if (asset == null) + continue; + + var animationAsset = asset as AnimationPlayableAsset; + if (animationAsset != null) + animationAsset.appliedOffsetMode = mode; + + var source = asset.CreatePlayable(graph, go); + if (source.IsValid()) + { + var clip = new RuntimeClip(c, source, mixer); + tree.Add(clip); + graph.Connect(source, 0, mixer, i); + mixer.SetInputWeight(i, 0.0f); + } + } + + return ApplyTrackOffset(graph, mixer, go, mode); + } + + Playable ILayerable.CreateLayerMixer(PlayableGraph graph, GameObject go, int inputCount) + { + return Playable.Null; + } + + internal override Playable OnCreateClipPlayableGraph(PlayableGraph graph, GameObject go, IntervalTree<RuntimeElement> tree) + { + if (isSubTrack) + throw new InvalidOperationException("Nested animation tracks should never be asked to create a graph directly"); + + List<AnimationTrack> flattenTracks = new List<AnimationTrack>(); + if (CanCompileClips()) + flattenTracks.Add(this); + + + bool animatesRootTransform = AnimatesRootTransform(); + foreach (var subTrack in GetChildTracks()) + { + var child = subTrack as AnimationTrack; + if (child != null && child.CanCompileClips()) + { + animatesRootTransform |= child.AnimatesRootTransform(); + flattenTracks.Add(child); + } + } + + // figure out which mode to apply + AppliedOffsetMode mode = GetOffsetMode(go, animatesRootTransform); + var layerMixer = CreateGroupMixer(graph, go, flattenTracks.Count); + for (int c = 0; c < flattenTracks.Count; c++) + { + var compiledTrackPlayable = flattenTracks[c].inClipMode ? + CompileTrackPlayable(graph, flattenTracks[c], go, tree, mode) : + flattenTracks[c].CreateInfiniteTrackPlayable(graph, go, tree, mode); + graph.Connect(compiledTrackPlayable, 0, layerMixer, c); + layerMixer.SetInputWeight(c, flattenTracks[c].inClipMode ? 0 : 1); + if (flattenTracks[c].applyAvatarMask && flattenTracks[c].avatarMask != null) + { + layerMixer.SetLayerMaskFromAvatarMask((uint)c, flattenTracks[c].avatarMask); + } + } + + bool requiresMotionXPlayable = RequiresMotionXPlayable(mode, go); + + Playable mixer = layerMixer; + mixer = CreateDefaultBlend(graph, go, mixer, requiresMotionXPlayable); + + // motionX playable not required in scene offset mode, or root transform mode + if (requiresMotionXPlayable) + { + // If we are animating a root transform, add the motionX to delta playable as the root node + var motionXToDelta = AnimationMotionXToDeltaPlayable.Create(graph); + graph.Connect(mixer, 0, motionXToDelta, 0); + motionXToDelta.SetInputWeight(0, 1.0f); + motionXToDelta.SetAbsoluteMotion(UsesAbsoluteMotion(mode)); + mixer = (Playable)motionXToDelta; + } + + +#if UNITY_EDITOR + if (!Application.isPlaying) + { + var animator = GetBinding(go != null ? go.GetComponent<PlayableDirector>() : null); + if (animator != null) + { + GameObject targetGO = animator.gameObject; + IAnimationWindowPreview[] previewComponents = targetGO.GetComponents<IAnimationWindowPreview>(); + + m_HasPreviewComponents = previewComponents.Length > 0; + if (m_HasPreviewComponents) + { + foreach (var component in previewComponents) + { + mixer = component.BuildPreviewGraph(graph, mixer); + } + } + } + } +#endif + + return mixer; + } + + // Creates a layer mixer containing default blends + // the base layer is a default clip of all driven properties + // the next layer is optionally the desired default pose (in the case of humanoid, the tpose + private Playable CreateDefaultBlend(PlayableGraph graph, GameObject go, Playable mixer, bool requireOffset) + { +#if UNITY_EDITOR + if (Application.isPlaying) + return mixer; + + int inputs = 1 + ((m_CachedPropertiesClip != null) ? 1 : 0) + ((m_DefaultPoseClip != null) ? 1 : 0); + if (inputs == 1) + return mixer; + + var defaultPoseMixer = AnimationLayerMixerPlayable.Create(graph, inputs); + + int mixerInput = 0; + if (m_CachedPropertiesClip) + { + var cachedPropertiesClip = AnimationClipPlayable.Create(graph, m_CachedPropertiesClip); + cachedPropertiesClip.SetApplyFootIK(false); + var defaults = (Playable) cachedPropertiesClip; + if (requireOffset) + defaults = AttachOffsetPlayable(graph, defaults, m_SceneOffsetPosition, Quaternion.Euler(m_SceneOffsetRotation)); + graph.Connect(defaults, 0, defaultPoseMixer, mixerInput); + defaultPoseMixer.SetInputWeight(mixerInput, 1.0f); + mixerInput++; + } + + if (m_DefaultPoseClip) + { + var defaultPose = AnimationClipPlayable.Create(graph, m_DefaultPoseClip); + defaultPose.SetApplyFootIK(false); + var blendDefault = (Playable) defaultPose; + if (requireOffset) + blendDefault = AttachOffsetPlayable(graph, blendDefault, m_SceneOffsetPosition, Quaternion.Euler(m_SceneOffsetRotation)); + + graph.Connect(blendDefault, 0, defaultPoseMixer, mixerInput); + defaultPoseMixer.SetInputWeight(mixerInput, 1.0f); + mixerInput++; + } + + + graph.Connect(mixer, 0, defaultPoseMixer, mixerInput); + defaultPoseMixer.SetInputWeight(mixerInput, 1.0f); + + return defaultPoseMixer; +#else + return mixer; +#endif + } + + private Playable AttachOffsetPlayable(PlayableGraph graph, Playable playable, Vector3 pos, Quaternion rot) + { + var offsetPlayable = AnimationOffsetPlayable.Create(graph, pos, rot, 1); + offsetPlayable.SetInputWeight(0, 1.0f); + graph.Connect(playable, 0, offsetPlayable, 0); + return offsetPlayable; + } + +#if UNITY_EDITOR + private static string k_DefaultHumanoidClipPath = "Packages/com.unity.timeline/Editor/StyleSheets/res/HumanoidDefault.anim"; + private static AnimationClip s_DefaultHumanoidClip = null; + + AnimationClip GetDefaultHumanoidClip() + { + if (s_DefaultHumanoidClip == null) + { + s_DefaultHumanoidClip = EditorGUIUtility.LoadRequired(k_DefaultHumanoidClipPath) as AnimationClip; + if (s_DefaultHumanoidClip == null) + Debug.LogError("Could not load default humanoid animation clip for Timeline"); + } + + return s_DefaultHumanoidClip; + } + +#endif + + bool RequiresMotionXPlayable(AppliedOffsetMode mode, GameObject gameObject) + { + if (mode == AppliedOffsetMode.NoRootTransform) + return false; + if (mode == AppliedOffsetMode.SceneOffsetLegacy) + { + var animator = GetBinding(gameObject != null ? gameObject.GetComponent<PlayableDirector>() : null); + return animator != null && animator.hasRootMotion; + } + return true; + } + + static bool UsesAbsoluteMotion(AppliedOffsetMode mode) + { +#if UNITY_EDITOR + // in editor, previewing is always done in absolute motion + if (!Application.isPlaying) + return true; +#endif + return mode != AppliedOffsetMode.SceneOffset && + mode != AppliedOffsetMode.SceneOffsetLegacy; + } + + bool HasController(GameObject gameObject) + { + var animator = GetBinding(gameObject != null ? gameObject.GetComponent<PlayableDirector>() : null); + + return animator != null && animator.runtimeAnimatorController != null; + } + + internal Animator GetBinding(PlayableDirector director) + { + if (director == null) + return null; + + UnityEngine.Object key = this; + if (isSubTrack) + key = parent; + + UnityEngine.Object binding = null; + if (director != null) + binding = director.GetGenericBinding(key); + + Animator animator = null; + if (binding != null) // the binding can be an animator or game object + { + animator = binding as Animator; + var gameObject = binding as GameObject; + if (animator == null && gameObject != null) + animator = gameObject.GetComponent<Animator>(); + } + + return animator; + } + + static AnimationLayerMixerPlayable CreateGroupMixer(PlayableGraph graph, GameObject go, int inputCount) + { + return AnimationLayerMixerPlayable.Create(graph, inputCount); + } + + Playable CreateInfiniteTrackPlayable(PlayableGraph graph, GameObject go, IntervalTree<RuntimeElement> tree, AppliedOffsetMode mode) + { + if (m_InfiniteClip == null) + return Playable.Null; + + var mixer = AnimationMixerPlayable.Create(graph, 1); + + // In infinite mode, we always force the loop mode of the clip off because the clip keys are offset in infinite mode + // which causes loop to behave different. + // The inline curve editor never shows loops in infinite mode. + var playable = AnimationPlayableAsset.CreatePlayable(graph, m_InfiniteClip, m_InfiniteClipOffsetPosition, m_InfiniteClipOffsetEulerAngles, false, mode, infiniteClipApplyFootIK, AnimationPlayableAsset.LoopMode.Off); + if (playable.IsValid()) + { + tree.Add(new InfiniteRuntimeClip(playable)); + graph.Connect(playable, 0, mixer, 0); + mixer.SetInputWeight(0, 1.0f); + } + + return ApplyTrackOffset(graph, mixer, go, mode); + } + + Playable ApplyTrackOffset(PlayableGraph graph, Playable root, GameObject go, AppliedOffsetMode mode) + { +#if UNITY_EDITOR + m_ClipOffset = AnimationOffsetPlayable.Null; +#endif + + // offsets don't apply in scene offset, or if there is no root transform (globally or on this track) + if (mode == AppliedOffsetMode.SceneOffsetLegacy || + mode == AppliedOffsetMode.SceneOffset || + mode == AppliedOffsetMode.NoRootTransform || + !AnimatesRootTransform() + ) + return root; + + + var pos = position; + var rot = rotation; + +#if UNITY_EDITOR + // in the editor use the preview position to playback from if available + if (mode == AppliedOffsetMode.SceneOffsetEditor) + { + pos = m_SceneOffsetPosition; + rot = Quaternion.Euler(m_SceneOffsetRotation); + } +#endif + + var offsetPlayable = AnimationOffsetPlayable.Create(graph, pos, rot, 1); +#if UNITY_EDITOR + m_ClipOffset = offsetPlayable; +#endif + graph.Connect(root, 0, offsetPlayable, 0); + offsetPlayable.SetInputWeight(0, 1); + + return offsetPlayable; + } + + // the evaluation time is large so that the properties always get evaluated + internal override void GetEvaluationTime(out double outStart, out double outDuration) + { + if (inClipMode) + { + base.GetEvaluationTime(out outStart, out outDuration); + } + else + { + outStart = 0; + outDuration = TimelineClip.kMaxTimeValue; + } + } + + internal override void GetSequenceTime(out double outStart, out double outDuration) + { + if (inClipMode) + { + base.GetSequenceTime(out outStart, out outDuration); + } + else + { + outStart = 0; + outDuration = Math.Max(GetNotificationDuration(), TimeUtility.GetAnimationClipLength(m_InfiniteClip)); + } + } + + void AssignAnimationClip(TimelineClip clip, AnimationClip animClip) + { + if (clip == null || animClip == null) + return; + + if (animClip.legacy) + throw new InvalidOperationException("Legacy Animation Clips are not supported"); + + AnimationPlayableAsset asset = clip.asset as AnimationPlayableAsset; + if (asset != null) + { + asset.clip = animClip; + asset.name = animClip.name; + var duration = asset.duration; + if (!double.IsInfinity(duration) && duration >= TimelineClip.kMinDuration && duration < TimelineClip.kMaxTimeValue) + clip.duration = duration; + } + clip.displayName = animClip.name; + } + + /// <summary> + /// Called by the Timeline Editor to gather properties requiring preview. + /// </summary> + /// <param name="director">The PlayableDirector invoking the preview</param> + /// <param name="driver">PropertyCollector used to gather previewable properties</param> + public override void GatherProperties(PlayableDirector director, IPropertyCollector driver) + { +#if UNITY_EDITOR + m_SceneOffsetPosition = Vector3.zero; + m_SceneOffsetRotation = Vector3.zero; + + var animator = GetBinding(director); + if (animator == null) + return; + + var animClips = new List<AnimationClip>(this.clips.Length + 2); + GetAnimationClips(animClips); + + var hasHumanMotion = animClips.Exists(clip => clip.humanMotion); + + m_SceneOffsetPosition = animator.transform.localPosition; + m_SceneOffsetRotation = animator.transform.localEulerAngles; + + // Create default pose clip from collected properties + if (hasHumanMotion) + animClips.Add(GetDefaultHumanoidClip()); + + var bindings = AnimationPreviewUtilities.GetBindings(animator.gameObject, animClips); + + m_CachedPropertiesClip = AnimationPreviewUtilities.CreateDefaultClip(animator.gameObject, bindings); + AnimationPreviewUtilities.PreviewFromCurves(animator.gameObject, bindings); // faster to preview from curves then an animation clip + m_DefaultPoseClip = hasHumanMotion ? GetDefaultHumanoidClip() : null; +#endif + } + + /// <summary> + /// Gather all the animation clips for this track + /// </summary> + /// <param name="animClips"></param> + private void GetAnimationClips(List<AnimationClip> animClips) + { + foreach (var c in clips) + { + var a = c.asset as AnimationPlayableAsset; + if (a != null && a.clip != null) + animClips.Add(a.clip); + } + + if (m_InfiniteClip != null) + animClips.Add(m_InfiniteClip); + + foreach (var childTrack in GetChildTracks()) + { + var animChildTrack = childTrack as AnimationTrack; + if (animChildTrack != null) + animChildTrack.GetAnimationClips(animClips); + } + } + + // calculate which offset mode to apply + AppliedOffsetMode GetOffsetMode(GameObject go, bool animatesRootTransform) + { + if (!animatesRootTransform) + return AppliedOffsetMode.NoRootTransform; + + if (m_TrackOffset == TrackOffset.ApplyTransformOffsets) + return AppliedOffsetMode.TransformOffset; + + if (m_TrackOffset == TrackOffset.ApplySceneOffsets) + return (Application.isPlaying) ? AppliedOffsetMode.SceneOffset : AppliedOffsetMode.SceneOffsetEditor; + + if (HasController(go)) + { + if (!Application.isPlaying) + return AppliedOffsetMode.SceneOffsetLegacyEditor; + return AppliedOffsetMode.SceneOffsetLegacy; + } + + return AppliedOffsetMode.TransformOffsetLegacy; + } + + internal bool AnimatesRootTransform() + { + // infinite mode + if (AnimationPlayableAsset.HasRootTransforms(m_InfiniteClip)) + return true; + + // clip mode + foreach (var c in GetClips()) + { + var apa = c.asset as AnimationPlayableAsset; + if (apa != null && apa.hasRootTransforms) + return true; + } + + return false; + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/AnimationTrack.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/AnimationTrack.cs.meta new file mode 100644 index 0000000..9ba4e15 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/AnimationTrack.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d21dcc2386d650c4597f3633c75a1f98 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/ICurvesOwner.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/ICurvesOwner.cs new file mode 100644 index 0000000..8d61f57 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/ICurvesOwner.cs @@ -0,0 +1,15 @@ +namespace UnityEngine.Timeline +{ + interface ICurvesOwner + { + AnimationClip curves { get; } + bool hasCurves { get; } + double duration { get; } + void CreateCurves(string curvesClipName); + + string defaultCurvesName { get; } + Object asset { get; } + Object assetOwner { get; } + TrackAsset targetTrack { get; } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/ICurvesOwner.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/ICurvesOwner.cs.meta new file mode 100644 index 0000000..d5d95df --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Animation/ICurvesOwner.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 89b31ff5ca0a5eb4797ac65d43949807 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade.meta new file mode 100644 index 0000000..f5aba63 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0c04c8cb23b78e04492e0f310cdee93e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/AnimationPlayableAssetUpgrade.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/AnimationPlayableAssetUpgrade.cs new file mode 100644 index 0000000..5ba31f6 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/AnimationPlayableAssetUpgrade.cs @@ -0,0 +1,47 @@ +using System; + +namespace UnityEngine.Timeline +{ + partial class AnimationPlayableAsset : ISerializationCallbackReceiver + { + enum Versions + { + Initial = 0, + RotationAsEuler = 1, + } + static readonly int k_LatestVersion = (int)Versions.RotationAsEuler; + [SerializeField, HideInInspector] int m_Version; + + [SerializeField, Obsolete("Use m_RotationEuler Instead", false), HideInInspector] + private Quaternion m_Rotation = Quaternion.identity; // deprecated. now saves in euler angles + + void ISerializationCallbackReceiver.OnBeforeSerialize() + { + m_Version = k_LatestVersion; + } + + void ISerializationCallbackReceiver.OnAfterDeserialize() + { + if (m_Version < k_LatestVersion) + { + OnUpgradeFromVersion(m_Version); //upgrade derived classes + } + } + + void OnUpgradeFromVersion(int oldVersion) + { + if (oldVersion < (int)Versions.RotationAsEuler) + AnimationPlayableAssetUpgrade.ConvertRotationToEuler(this); + } + + static class AnimationPlayableAssetUpgrade + { + public static void ConvertRotationToEuler(AnimationPlayableAsset asset) + { +#pragma warning disable 618 + asset.m_EulerAngles = asset.m_Rotation.eulerAngles; +#pragma warning restore 618 + } + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/AnimationPlayableAssetUpgrade.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/AnimationPlayableAssetUpgrade.cs.meta new file mode 100644 index 0000000..867be5e --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/AnimationPlayableAssetUpgrade.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6773203120b27984d9a8572fa3564f03 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/AnimationTrackUpgrade.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/AnimationTrackUpgrade.cs new file mode 100644 index 0000000..94c5634 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/AnimationTrackUpgrade.cs @@ -0,0 +1,102 @@ +using System; +using System.ComponentModel; + +namespace UnityEngine.Timeline +{ + partial class AnimationTrack + { + // 649 is value is only assigned to. they can be updated from old files being serialized + #pragma warning disable 649 + //fields that are used for upgrading should be put here, ideally as read-only + [SerializeField, Obsolete("Use m_InfiniteClipOffsetEulerAngles Instead", false), HideInInspector] + Quaternion m_OpenClipOffsetRotation = Quaternion.identity; + + [SerializeField, Obsolete("Use m_RotationEuler Instead", false), HideInInspector] + Quaternion m_Rotation = Quaternion.identity; + + [SerializeField, Obsolete("Use m_RootTransformOffsetMode", false), HideInInspector] + bool m_ApplyOffsets; + #pragma warning restore 649 + + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete("openClipOffsetPosition has been deprecated. Use infiniteClipOffsetPosition instead. (UnityUpgradable) -> infiniteClipOffsetPosition", true)] + public Vector3 openClipOffsetPosition + { + get { return infiniteClipOffsetPosition; } + set { infiniteClipOffsetPosition = value; } + } + + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete("openClipOffsetRotation has been deprecated. Use infiniteClipOffsetRotation instead. (UnityUpgradable) -> infiniteClipOffsetRotation", true)] + public Quaternion openClipOffsetRotation + { + get { return infiniteClipOffsetRotation; } + set { infiniteClipOffsetRotation = value; } + } + + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete("openClipOffsetEulerAngles has been deprecated. Use infiniteClipOffsetEulerAngles instead. (UnityUpgradable) -> infiniteClipOffsetEulerAngles", true)] + public Vector3 openClipOffsetEulerAngles + { + get { return infiniteClipOffsetEulerAngles; } + set { infiniteClipOffsetEulerAngles = value; } + } + + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete("openClipPreExtrapolation has been deprecated. Use infiniteClipPreExtrapolation instead. (UnityUpgradable) -> infiniteClipPreExtrapolation", true)] + public TimelineClip.ClipExtrapolation openClipPreExtrapolation + { + get { return infiniteClipPreExtrapolation; } + set { infiniteClipPreExtrapolation = value; } + } + + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete("openClipPostExtrapolation has been deprecated. Use infiniteClipPostExtrapolation instead. (UnityUpgradable) -> infiniteClipPostExtrapolation", true)] + public TimelineClip.ClipExtrapolation openClipPostExtrapolation + { + get { return infiniteClipPostExtrapolation; } + set { infiniteClipPostExtrapolation = value; } + } + + internal override void OnUpgradeFromVersion(int oldVersion) + { + if (oldVersion < (int)Versions.RotationAsEuler) + AnimationTrackUpgrade.ConvertRotationsToEuler(this); + if (oldVersion < (int)Versions.RootMotionUpgrade) + AnimationTrackUpgrade.ConvertRootMotion(this); + if (oldVersion < (int)Versions.AnimatedTrackProperties) + AnimationTrackUpgrade.ConvertInfiniteTrack(this); + } + +// 612 is Property is Obsolete +// 618 is Field is Obsolete +#pragma warning disable 612, 618 + static class AnimationTrackUpgrade + { + public static void ConvertRotationsToEuler(AnimationTrack track) + { + track.m_EulerAngles = track.m_Rotation.eulerAngles; + track.m_InfiniteClipOffsetEulerAngles = track.m_OpenClipOffsetRotation.eulerAngles; + } + + public static void ConvertRootMotion(AnimationTrack track) + { + track.m_TrackOffset = TrackOffset.Auto; // loaded tracks should use legacy mode + + // reset offsets if not applied + if (!track.m_ApplyOffsets) + { + track.m_Position = Vector3.zero; + track.m_EulerAngles = Vector3.zero; + } + } + + public static void ConvertInfiniteTrack(AnimationTrack track) + { + track.m_InfiniteClip = track.m_AnimClip; + track.m_AnimClip = null; + } + } +#pragma warning restore 612, 618 + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/AnimationTrackUpgrade.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/AnimationTrackUpgrade.cs.meta new file mode 100644 index 0000000..01b86a7 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/AnimationTrackUpgrade.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3b0c53b13a1539949b3b212e049151d1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/ClipUpgrade.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/ClipUpgrade.cs new file mode 100644 index 0000000..20f3dfd --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/ClipUpgrade.cs @@ -0,0 +1,34 @@ +namespace UnityEngine.Timeline +{ + partial class TimelineClip + { + enum Versions + { + Initial = 0, + ClipInFromGlobalToLocal = 1 + } + const int k_LatestVersion = (int)Versions.ClipInFromGlobalToLocal; + [SerializeField, HideInInspector] int m_Version; + + //fields that are used for upgrading should be put here, ideally as read-only + + void UpgradeToLatestVersion() + { + if (m_Version < (int)Versions.ClipInFromGlobalToLocal) + { + TimelineClipUpgrade.UpgradeClipInFromGlobalToLocal(this); + } + } + + static class TimelineClipUpgrade + { + // version 0->1, clipIn move from global to local + public static void UpgradeClipInFromGlobalToLocal(TimelineClip clip) + { + // case 936751 -- clipIn was serialized in global, not local offset + if (clip.m_ClipIn > 0 && clip.m_TimeScale > float.Epsilon) + clip.m_ClipIn *= clip.m_TimeScale; + } + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/ClipUpgrade.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/ClipUpgrade.cs.meta new file mode 100644 index 0000000..0b27935 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/ClipUpgrade.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6a4f0c91a28ece04198b200dd55145d0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/TimelineUpgrade.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/TimelineUpgrade.cs new file mode 100644 index 0000000..86135c6 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/TimelineUpgrade.cs @@ -0,0 +1,21 @@ +namespace UnityEngine.Timeline +{ + partial class TimelineAsset + { + enum Versions + { + Initial = 0 + } + const int k_LatestVersion = (int)Versions.Initial; + [SerializeField, HideInInspector] int m_Version; + + //fields that are used for upgrading should be put here, ideally as read-only + + void UpgradeToLatestVersion() + {} + + //upgrade code should go into this class + static class TimelineAssetUpgrade + {} + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/TimelineUpgrade.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/TimelineUpgrade.cs.meta new file mode 100644 index 0000000..6075bab --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/TimelineUpgrade.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 95c91abdcc1ea03458c2ea4e9626a5d8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/TrackUpgrade.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/TrackUpgrade.cs new file mode 100644 index 0000000..6768199 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/TrackUpgrade.cs @@ -0,0 +1,76 @@ +using System; +using UnityEngine.Serialization; + +namespace UnityEngine.Timeline +{ + partial class TrackAsset : ISerializationCallbackReceiver + { + internal enum Versions + { + Initial = 0, + RotationAsEuler = 1, + RootMotionUpgrade = 2, + AnimatedTrackProperties = 3 + } + + const int k_LatestVersion = (int)Versions.AnimatedTrackProperties; + + [SerializeField, HideInInspector] int m_Version; + + [Obsolete("Please use m_InfiniteClip (on AnimationTrack) instead.", false)] + [SerializeField, HideInInspector, FormerlySerializedAs("m_animClip")] + internal AnimationClip m_AnimClip; + + protected virtual void OnBeforeTrackSerialize() {} + protected virtual void OnAfterTrackDeserialize() {} + + internal virtual void OnUpgradeFromVersion(int oldVersion) {} + + void ISerializationCallbackReceiver.OnBeforeSerialize() + { + m_Version = k_LatestVersion; + + //make sure children are correctly parented + if (m_Children != null) + { + for (var i = m_Children.Count - 1; i >= 0; i--) + { + var asset = m_Children[i] as TrackAsset; + if (asset != null && asset.parent != this) + asset.parent = this; + } + } + + OnBeforeTrackSerialize(); + } + + void ISerializationCallbackReceiver.OnAfterDeserialize() + { + // Clear the clip cache when a deserialize is performed, or + // we can get out of sync when performing Undo + m_ClipsCache = null; + Invalidate(); + + if (m_Version < k_LatestVersion) + { + UpgradeToLatestVersion(); //upgrade TrackAsset + OnUpgradeFromVersion(m_Version); //upgrade derived classes + } + + foreach (var marker in GetMarkers()) + { + marker.Initialize(this); + } + + OnAfterTrackDeserialize(); + } + + //fields that are used for upgrading should be put here, ideally as read-only + void UpgradeToLatestVersion() + {} + + //upgrade code should go into this class + static class TrackAssetUpgrade + {} + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/TrackUpgrade.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/TrackUpgrade.cs.meta new file mode 100644 index 0000000..bbe22f0 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/AssetUpgrade/TrackUpgrade.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c68f34993bfe85e489158a29c99a20b5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Attributes.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Attributes.meta new file mode 100644 index 0000000..d77a179 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Attributes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ec817e5e5781e0a4983a1dc8875d1974 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Attributes/TrackColorAttribute.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Attributes/TrackColorAttribute.cs new file mode 100644 index 0000000..a6abc20 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Attributes/TrackColorAttribute.cs @@ -0,0 +1,33 @@ +using System; +using UnityEngine; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// Attribute used to specify the color of the track and its clips inside the Timeline Editor. + /// </summary> + [AttributeUsage(AttributeTargets.Class)] + public class TrackColorAttribute : Attribute + { + Color m_Color; + + /// <summary> + /// + /// </summary> + public Color color + { + get { return m_Color; } + } + + /// <summary> + /// Specify the track color using [0-1] R,G,B values. + /// </summary> + /// <param name="r">Red value [0-1].</param> + /// <param name="g">Green value [0-1].</param> + /// <param name="b">Blue value [0-1].</param> + public TrackColorAttribute(float r, float g, float b) + { + m_Color = new Color(r, g, b); + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Attributes/TrackColorAttribute.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Attributes/TrackColorAttribute.cs.meta new file mode 100644 index 0000000..80c61ba --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Attributes/TrackColorAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6c3d52cc5c46d7946a920e21901ff38e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio.meta new file mode 100644 index 0000000..b3fd165 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d19b75372f4e44d4fa4b2cffbb54124b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio/AudioClipProperties.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio/AudioClipProperties.cs new file mode 100644 index 0000000..0c5894b --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio/AudioClipProperties.cs @@ -0,0 +1,13 @@ +using System; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + [Serializable] + [NotKeyable] + class AudioClipProperties : PlayableBehaviour + { + [Range(0.0f, 1.0f)] + public float volume = 1.0f; + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio/AudioClipProperties.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio/AudioClipProperties.cs.meta new file mode 100644 index 0000000..a044757 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio/AudioClipProperties.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0d60a406ab64c434e9d731914e11a51e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio/AudioMixerProperties.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio/AudioMixerProperties.cs new file mode 100644 index 0000000..c5bdf8c --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio/AudioMixerProperties.cs @@ -0,0 +1,45 @@ +using System; +using UnityEngine.Audio; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + [Serializable] + class AudioMixerProperties : PlayableBehaviour + { + [Range(0.0f, 1.0f)] + public float volume = 1.0f; + + [Range(-1.0f, 1.0f)] + public float stereoPan = 0.0f; + + [Range(0.0f, 1.0f)] + public float spatialBlend = 0.0f; + + public override void PrepareFrame(Playable playable, FrameData info) + { + if (!playable.IsValid() || !playable.IsPlayableOfType<AudioMixerPlayable>()) + return; + + var inputCount = playable.GetInputCount(); + + for (int i = 0; i < inputCount; ++i) + { + if (playable.GetInputWeight(i) > 0.0f) + { + var input = playable.GetInput(i); + + if (input.IsValid() && input.IsPlayableOfType<AudioClipPlayable>()) + { + var audioClipPlayable = (AudioClipPlayable)input; + var audioClipProperties = input.GetHandle().GetObject<AudioClipProperties>(); + + audioClipPlayable.SetVolume(Mathf.Clamp01(volume * audioClipProperties.volume)); + audioClipPlayable.SetStereoPan(Mathf.Clamp(stereoPan, -1.0f, 1.0f)); + audioClipPlayable.SetSpatialBlend(Mathf.Clamp01(spatialBlend)); + } + } + } + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio/AudioMixerProperties.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio/AudioMixerProperties.cs.meta new file mode 100644 index 0000000..fa975ef --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio/AudioMixerProperties.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d8c4a920f001ca64680ed6fdb52d1753 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio/AudioPlayableAsset.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio/AudioPlayableAsset.cs new file mode 100644 index 0000000..7ff40fc --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio/AudioPlayableAsset.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using UnityEngine.Audio; +#if UNITY_EDITOR +using System.ComponentModel; +#endif +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// PlayableAsset wrapper for an AudioClip in Timeline. + /// </summary> + [Serializable] +#if UNITY_EDITOR + [DisplayName("Audio Clip")] +#endif + public class AudioPlayableAsset : PlayableAsset, ITimelineClipAsset + { + [SerializeField] AudioClip m_Clip; +#pragma warning disable 649 //Field is never assigned to and will always have its default value + [SerializeField] bool m_Loop; + [SerializeField, HideInInspector] float m_bufferingTime = 0.1f; + [SerializeField] AudioClipProperties m_ClipProperties = new AudioClipProperties(); + + // the amount of time to give the clip to load prior to it's start time + internal float bufferingTime + { + get { return m_bufferingTime; } + set { m_bufferingTime = value; } + } + +#if UNITY_EDITOR + Playable m_LiveClipPlayable = Playable.Null; + +#endif + + /// <summary> + /// The audio clip to be played + /// </summary> + public AudioClip clip + { + get { return m_Clip; } + set { m_Clip = value; } + } + + /// <summary> + /// Whether the audio clip loops. + /// </summary> + /// <remarks> + /// Use this to loop the audio clip when the duration of the timeline clip exceeds that of the audio clip. + /// </remarks> + public bool loop + { + get { return m_Loop; } + set { m_Loop = value; } + } + + /// <summary> + /// Returns the duration required to play the audio clip exactly once + /// </summary> + public override double duration + { + get + { + if (m_Clip == null) + return base.duration; + + // use this instead of length to avoid rounding precision errors, + return (double)m_Clip.samples / m_Clip.frequency; + } + } + + /// <summary> + /// Returns a description of the PlayableOutputs that may be created for this asset. + /// </summary> + public override IEnumerable<PlayableBinding> outputs + { + get { yield return AudioPlayableBinding.Create(name, this); } + } + + /// <summary> + /// Creates the root of a Playable subgraph to play the audio clip. + /// </summary> + /// <param name="graph">PlayableGraph that will own the playable</param> + /// <param name="go">The GameObject that triggered the graph build</param> + /// <returns>The root playable of the subgraph</returns> + public override Playable CreatePlayable(PlayableGraph graph, GameObject go) + { + if (m_Clip == null) + return Playable.Null; + + var audioClipPlayable = AudioClipPlayable.Create(graph, m_Clip, m_Loop); + audioClipPlayable.GetHandle().SetScriptInstance(m_ClipProperties.Clone()); + +#if UNITY_EDITOR + m_LiveClipPlayable = audioClipPlayable; +#endif + + return audioClipPlayable; + } + + /// <summary> + /// Returns the capabilities of TimelineClips that contain an AudioPlayableAsset + /// </summary> + public ClipCaps clipCaps + { + get + { + return ClipCaps.ClipIn | + ClipCaps.SpeedMultiplier | + ClipCaps.Blending | + (m_Loop ? ClipCaps.Looping : ClipCaps.None); + } + } + +#if UNITY_EDITOR + internal void LiveLink() + { + if (!m_LiveClipPlayable.IsValid()) + return; + + var audioMixerProperties = m_LiveClipPlayable.GetHandle().GetObject<AudioClipProperties>(); + + if (audioMixerProperties == null) + return; + + audioMixerProperties.volume = m_ClipProperties.volume; + } + +#endif + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio/AudioPlayableAsset.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio/AudioPlayableAsset.cs.meta new file mode 100644 index 0000000..1b64816 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio/AudioPlayableAsset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4f10dd60657c6004587f237a7e90f8e4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio/AudioTrack.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio/AudioTrack.cs new file mode 100644 index 0000000..d35fac6 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio/AudioTrack.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; +using UnityEngine.Audio; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// A Timeline track that can play AudioClips. + /// </summary> + [Serializable] + [TrackClipType(typeof(AudioPlayableAsset), false)] + [TrackBindingType(typeof(AudioSource))] + [ExcludeFromPreset] + public class AudioTrack : TrackAsset + { + [SerializeField] + AudioMixerProperties m_TrackProperties = new AudioMixerProperties(); + +#if UNITY_EDITOR + Playable m_LiveMixerPlayable = Playable.Null; + +#endif + + /// <summary> + /// Create an TimelineClip for playing an AudioClip on this track. + /// </summary> + /// <param name="clip">The audio clip to play</param> + /// <returns>A TimelineClip with an AudioPlayableAsset asset.</returns> + public TimelineClip CreateClip(AudioClip clip) + { + if (clip == null) + return null; + + var newClip = CreateDefaultClip(); + + var audioAsset = newClip.asset as AudioPlayableAsset; + if (audioAsset != null) + audioAsset.clip = clip; + + newClip.duration = clip.length; + newClip.displayName = clip.name; + + return newClip; + } + + internal override Playable CompileClips(PlayableGraph graph, GameObject go, IList<TimelineClip> timelineClips, IntervalTree<RuntimeElement> tree) + { + var clipBlender = AudioMixerPlayable.Create(graph, timelineClips.Count); + +#if UNITY_EDITOR + clipBlender.GetHandle().SetScriptInstance(m_TrackProperties.Clone()); + m_LiveMixerPlayable = clipBlender; +#else + if (hasCurves) + clipBlender.GetHandle().SetScriptInstance(m_TrackProperties.Clone()); +#endif + + for (int i = 0; i < timelineClips.Count; i++) + { + var c = timelineClips[i]; + var asset = c.asset as PlayableAsset; + if (asset == null) + continue; + + var buffer = 0.1f; + var audioAsset = c.asset as AudioPlayableAsset; + if (audioAsset != null) + buffer = audioAsset.bufferingTime; + + var source = asset.CreatePlayable(graph, go); + if (!source.IsValid()) + continue; + + if (source.IsPlayableOfType<AudioClipPlayable>()) + { + // Enforce initial values on all clips + var audioClipPlayable = (AudioClipPlayable)source; + var audioClipProperties = audioClipPlayable.GetHandle().GetObject<AudioClipProperties>(); + + audioClipPlayable.SetVolume(Mathf.Clamp01(m_TrackProperties.volume * audioClipProperties.volume)); + audioClipPlayable.SetStereoPan(Mathf.Clamp(m_TrackProperties.stereoPan, -1.0f, 1.0f)); + audioClipPlayable.SetSpatialBlend(Mathf.Clamp01(m_TrackProperties.spatialBlend)); + } + + tree.Add(new ScheduleRuntimeClip(c, source, clipBlender, buffer)); + graph.Connect(source, 0, clipBlender, i); + source.SetSpeed(c.timeScale); + source.SetDuration(c.extrapolatedDuration); + clipBlender.SetInputWeight(source, 1.0f); + } + + ConfigureTrackAnimation(tree, go, clipBlender); + + return clipBlender; + } + + /// <inheritdoc/> + public override IEnumerable<PlayableBinding> outputs + { + get { yield return AudioPlayableBinding.Create(name, this); } + } + +#if UNITY_EDITOR + internal void LiveLink() + { + if (!m_LiveMixerPlayable.IsValid()) + return; + + var audioMixerProperties = m_LiveMixerPlayable.GetHandle().GetObject<AudioMixerProperties>(); + + if (audioMixerProperties == null) + return; + + audioMixerProperties.volume = m_TrackProperties.volume; + audioMixerProperties.stereoPan = m_TrackProperties.stereoPan; + audioMixerProperties.spatialBlend = m_TrackProperties.spatialBlend; + } + +#endif + + void OnValidate() + { + m_TrackProperties.volume = Mathf.Clamp01(m_TrackProperties.volume); + m_TrackProperties.stereoPan = Mathf.Clamp(m_TrackProperties.stereoPan, -1.0f, 1.0f); + m_TrackProperties.spatialBlend = Mathf.Clamp01(m_TrackProperties.spatialBlend); + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio/AudioTrack.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio/AudioTrack.cs.meta new file mode 100644 index 0000000..2a826c9 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Audio/AudioTrack.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8b22792c3b570444eb18cb78c2af3a74 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/ClipCaps.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/ClipCaps.cs new file mode 100644 index 0000000..2a5efb6 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/ClipCaps.cs @@ -0,0 +1,85 @@ +using System; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// Describes the timeline features supported by a clip + /// </summary> + [Flags] + public enum ClipCaps + { + /// <summary> + /// No features are supported. + /// </summary> + None = 0 , + + /// <summary> + /// The clip supports loops. + /// </summary> + Looping = 1 << 0, + + /// <summary> + /// The clip supports clip extrapolation. + /// </summary> + Extrapolation = 1 << 1, + + /// <summary> + /// The clip supports initial local times greater than zero. + /// </summary> + ClipIn = 1 << 2, + + /// <summary> + /// The clip supports time scaling. + /// </summary> + SpeedMultiplier = 1 << 3, + + /// <summary> + /// The clip supports blending between clips. + /// </summary> + Blending = 1 << 4, + + /// <summary> + /// All features are supported. + /// </summary> + All = ~None + } + + static class TimelineClipCapsExtensions + { + public static bool SupportsLooping(this TimelineClip clip) + { + return clip != null && (clip.clipCaps & ClipCaps.Looping) != ClipCaps.None; + } + + public static bool SupportsExtrapolation(this TimelineClip clip) + { + return clip != null && (clip.clipCaps & ClipCaps.Extrapolation) != ClipCaps.None; + } + + public static bool SupportsClipIn(this TimelineClip clip) + { + return clip != null && (clip.clipCaps & ClipCaps.ClipIn) != ClipCaps.None; + } + + public static bool SupportsSpeedMultiplier(this TimelineClip clip) + { + return clip != null && (clip.clipCaps & ClipCaps.SpeedMultiplier) != ClipCaps.None; + } + + public static bool SupportsBlending(this TimelineClip clip) + { + return clip != null && (clip.clipCaps & ClipCaps.Blending) != ClipCaps.None; + } + + public static bool HasAll(this ClipCaps caps, ClipCaps flags) + { + return (caps & flags) == flags; + } + + public static bool HasAny(this ClipCaps caps, ClipCaps flags) + { + return (caps & flags) != 0; + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/ClipCaps.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/ClipCaps.cs.meta new file mode 100644 index 0000000..ba03648 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/ClipCaps.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 667a99762bdf5484fbaa02573fd396e2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Control.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Control.meta new file mode 100644 index 0000000..e4a557d --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Control.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ea998292f45ea494d9e100f5f6362f91 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Control/ControlPlayableAsset.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Control/ControlPlayableAsset.cs new file mode 100644 index 0000000..fd806f6 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Control/ControlPlayableAsset.cs @@ -0,0 +1,406 @@ +using System; +using System.Collections.Generic; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// Playable Asset that generates playables for controlling time-related elements on a GameObject. + /// </summary> + [Serializable] + [NotKeyable] + public class ControlPlayableAsset : PlayableAsset, IPropertyPreview, ITimelineClipAsset + { + const int k_MaxRandInt = 10000; + static readonly List<PlayableDirector> k_EmptyDirectorsList = new List<PlayableDirector>(0); + static readonly List<ParticleSystem> k_EmptyParticlesList = new List<ParticleSystem>(0); + + /// <summary> + /// GameObject in the scene to control, or the parent of the instantiated prefab. + /// </summary> + [SerializeField] public ExposedReference<GameObject> sourceGameObject; + + /// <summary> + /// Prefab object that will be instantiated. + /// </summary> + [SerializeField] public GameObject prefabGameObject; + + /// <summary> + /// Indicates whether Particle Systems will be controlled. + /// </summary> + [SerializeField] public bool updateParticle = true; + + /// <summary> + /// Random seed to supply particle systems that are set to use autoRandomSeed + /// </summary> + /// <remarks> + /// This is used to maintain determinism when playing back in timeline. Sub emitters will be assigned incrementing random seeds to maintain determinism and distinction. + /// </remarks> + [SerializeField] public uint particleRandomSeed; + + /// <summary> + /// Indicates whether playableDirectors are controlled. + /// </summary> + [SerializeField] public bool updateDirector = true; + + /// <summary> + /// Indicates whether Monobehaviours implementing ITimeControl will be controlled. + /// </summary> + [SerializeField] public bool updateITimeControl = true; + + /// <summary> + /// Indicates whether to search the entire hierarchy for controllable components. + /// </summary> + [SerializeField] public bool searchHierarchy = false; + + /// <summary> + /// Indicate whether GameObject activation is controlled + /// </summary> + [SerializeField] public bool active = true; + + /// <summary> + /// Indicates the active state of the GameObject when Timeline is stopped. + /// </summary> + [SerializeField] public ActivationControlPlayable.PostPlaybackState postPlayback = ActivationControlPlayable.PostPlaybackState.Revert; + + PlayableAsset m_ControlDirectorAsset; + double m_Duration = PlayableBinding.DefaultDuration; + bool m_SupportLoop; + + private static HashSet<PlayableDirector> s_ProcessedDirectors = new HashSet<PlayableDirector>(); + private static HashSet<GameObject> s_CreatedPrefabs = new HashSet<GameObject>(); + + // does the last instance created control directors and/or particles + internal bool controllingDirectors { get; private set; } + internal bool controllingParticles { get; private set; } + + /// <summary> + /// This function is called when the object is loaded. + /// </summary> + public void OnEnable() + { + // can't be set in a constructor + if (particleRandomSeed == 0) + particleRandomSeed = (uint)Random.Range(1, k_MaxRandInt); + } + + /// <summary> + /// Returns the duration in seconds needed to play the underlying director or particle system exactly once. + /// </summary> + public override double duration { get { return m_Duration; } } + + /// <summary> + /// Returns the capabilities of TimelineClips that contain a ControlPlayableAsset + /// </summary> + public ClipCaps clipCaps + { + get { return ClipCaps.ClipIn | ClipCaps.SpeedMultiplier | (m_SupportLoop ? ClipCaps.Looping : ClipCaps.None); } + } + + /// <summary> + /// Creates the root of a Playable subgraph to control the contents of the game object. + /// </summary> + /// <param name="graph">PlayableGraph that will own the playable</param> + /// <param name="go">The GameObject that triggered the graph build</param> + /// <returns>The root playable of the subgraph</returns> + public override Playable CreatePlayable(PlayableGraph graph, GameObject go) + { + // case 989856 + if (prefabGameObject != null) + { + if (s_CreatedPrefabs.Contains(prefabGameObject)) + { + Debug.LogWarningFormat("Control Track Clip ({0}) is causing a prefab to instantiate itself recursively. Aborting further instances.", name); + return Playable.Create(graph); + } + s_CreatedPrefabs.Add(prefabGameObject); + } + + Playable root = Playable.Null; + var playables = new List<Playable>(); + + GameObject sourceObject = sourceGameObject.Resolve(graph.GetResolver()); + if (prefabGameObject != null) + { + Transform parenTransform = sourceObject != null ? sourceObject.transform : null; + var controlPlayable = PrefabControlPlayable.Create(graph, prefabGameObject, parenTransform); + + sourceObject = controlPlayable.GetBehaviour().prefabInstance; + playables.Add(controlPlayable); + } + + m_Duration = PlayableBinding.DefaultDuration; + m_SupportLoop = false; + + controllingParticles = false; + controllingDirectors = false; + + if (sourceObject != null) + { + var directors = updateDirector ? GetComponent<PlayableDirector>(sourceObject) : k_EmptyDirectorsList; + var particleSystems = updateParticle ? GetParticleSystemRoots(sourceObject) : k_EmptyParticlesList; + + // update the duration and loop values (used for UI purposes) here + // so they are tied to the latest gameObject bound + UpdateDurationAndLoopFlag(directors, particleSystems); + + var director = go.GetComponent<PlayableDirector>(); + if (director != null) + m_ControlDirectorAsset = director.playableAsset; + + if (go == sourceObject && prefabGameObject == null) + { + Debug.LogWarningFormat("Control Playable ({0}) is referencing the same PlayableDirector component than the one in which it is playing.", name); + active = false; + if (!searchHierarchy) + updateDirector = false; + } + + if (active) + CreateActivationPlayable(sourceObject, graph, playables); + + if (updateDirector) + SearchHierarchyAndConnectDirector(directors, graph, playables, prefabGameObject != null); + + if (updateParticle) + SearchHiearchyAndConnectParticleSystem(particleSystems, graph, playables); + + if (updateITimeControl) + SearchHierarchyAndConnectControlableScripts(GetControlableScripts(sourceObject), graph, playables); + + // Connect Playables to Generic to Mixer + root = ConnectPlayablesToMixer(graph, playables); + } + + if (prefabGameObject != null) + s_CreatedPrefabs.Remove(prefabGameObject); + + if (!root.IsValid()) + root = Playable.Create(graph); + + return root; + } + + static Playable ConnectPlayablesToMixer(PlayableGraph graph, List<Playable> playables) + { + var mixer = Playable.Create(graph, playables.Count); + + for (int i = 0; i != playables.Count; ++i) + { + ConnectMixerAndPlayable(graph, mixer, playables[i], i); + } + + mixer.SetPropagateSetTime(true); + + return mixer; + } + + void CreateActivationPlayable(GameObject root, PlayableGraph graph, + List<Playable> outplayables) + { + var activation = ActivationControlPlayable.Create(graph, root, postPlayback); + if (activation.IsValid()) + outplayables.Add(activation); + } + + void SearchHiearchyAndConnectParticleSystem(IEnumerable<ParticleSystem> particleSystems, PlayableGraph graph, + List<Playable> outplayables) + { + foreach (var particleSystem in particleSystems) + { + if (particleSystem != null) + { + controllingParticles = true; + outplayables.Add(ParticleControlPlayable.Create(graph, particleSystem, particleRandomSeed)); + } + } + } + + void SearchHierarchyAndConnectDirector(IEnumerable<PlayableDirector> directors, PlayableGraph graph, + List<Playable> outplayables, bool disableSelfReferences) + { + foreach (var director in directors) + { + if (director != null) + { + if (director.playableAsset != m_ControlDirectorAsset) + { + outplayables.Add(DirectorControlPlayable.Create(graph, director)); + controllingDirectors = true; + } + // if this self references, disable the director. + else if (disableSelfReferences) + { + director.enabled = false; + } + } + } + } + + static void SearchHierarchyAndConnectControlableScripts(IEnumerable<MonoBehaviour> controlableScripts, PlayableGraph graph, List<Playable> outplayables) + { + foreach (var script in controlableScripts) + { + outplayables.Add(TimeControlPlayable.Create(graph, (ITimeControl)script)); + } + } + + static void ConnectMixerAndPlayable(PlayableGraph graph, Playable mixer, Playable playable, + int portIndex) + { + graph.Connect(playable, 0, mixer, portIndex); + mixer.SetInputWeight(playable, 1.0f); + } + + internal IList<T> GetComponent<T>(GameObject gameObject) + { + var components = new List<T>(); + if (gameObject != null) + { + if (searchHierarchy) + { + gameObject.GetComponentsInChildren<T>(true, components); + } + else + { + gameObject.GetComponents<T>(components); + } + } + return components; + } + + static IEnumerable<MonoBehaviour> GetControlableScripts(GameObject root) + { + if (root == null) + yield break; + + foreach (var script in root.GetComponentsInChildren<MonoBehaviour>()) + { + if (script is ITimeControl) + yield return script; + } + } + + internal void UpdateDurationAndLoopFlag(IList<PlayableDirector> directors, IList<ParticleSystem> particleSystems) + { + if (directors.Count == 0 && particleSystems.Count == 0) + return; + + const double invalidDuration = double.NegativeInfinity; + + var maxDuration = invalidDuration; + var supportsLoop = false; + + foreach (var director in directors) + { + if (director.playableAsset != null) + { + var assetDuration = director.playableAsset.duration; + + if (director.playableAsset is TimelineAsset && assetDuration > 0.0) + // Timeline assets report being one tick shorter than they actually are, unless they are empty + assetDuration = (double)((DiscreteTime)assetDuration).OneTickAfter(); + + maxDuration = Math.Max(maxDuration, assetDuration); + supportsLoop = supportsLoop || director.extrapolationMode == DirectorWrapMode.Loop; + } + } + + foreach (var particleSystem in particleSystems) + { + maxDuration = Math.Max(maxDuration, particleSystem.main.duration); + supportsLoop = supportsLoop || particleSystem.main.loop; + } + + m_Duration = double.IsNegativeInfinity(maxDuration) ? PlayableBinding.DefaultDuration : maxDuration; + m_SupportLoop = supportsLoop; + } + + IList<ParticleSystem> GetParticleSystemRoots(GameObject go) + { + if (searchHierarchy) + { + // We only want the parent systems as they will handle all the child systems. + var roots = new List<ParticleSystem>(); + GetParticleSystemRoots(go.transform, roots); + return roots; + } + return GetComponent<ParticleSystem>(go); + } + + static void GetParticleSystemRoots(Transform t, ICollection<ParticleSystem> roots) + { + var ps = t.GetComponent<ParticleSystem>(); + if (ps != null) + { + // its a root + roots.Add(ps); + return; + } + + for (int i = 0; i < t.childCount; ++i) + { + GetParticleSystemRoots(t.GetChild(i), roots); + } + } + + /// <inheritdoc/> + public void GatherProperties(PlayableDirector director, IPropertyCollector driver) + { + if (director == null) + return; + + // prevent infinite recursion + if (s_ProcessedDirectors.Contains(director)) + return; + s_ProcessedDirectors.Add(director); + + var gameObject = sourceGameObject.Resolve(director); + if (gameObject != null) + { + if (updateParticle) + { + // case 1076850 -- drive all emitters, not just roots. + foreach (var ps in gameObject.GetComponentsInChildren<ParticleSystem>(true)) + { + driver.AddFromName<ParticleSystem>(ps.gameObject, "randomSeed"); + driver.AddFromName<ParticleSystem>(ps.gameObject, "autoRandomSeed"); + } + } + + if (active) + { + driver.AddFromName(gameObject, "m_IsActive"); + } + + if (updateITimeControl) + { + foreach (var script in GetControlableScripts(gameObject)) + { + var propertyPreview = script as IPropertyPreview; + if (propertyPreview != null) + propertyPreview.GatherProperties(director, driver); + else + driver.AddFromComponent(script.gameObject, script); + } + } + + if (updateDirector) + { + foreach (var childDirector in GetComponent<PlayableDirector>(gameObject)) + { + if (childDirector == null) + continue; + + var timeline = childDirector.playableAsset as TimelineAsset; + if (timeline == null) + continue; + + timeline.GatherProperties(childDirector, driver); + } + } + } + s_ProcessedDirectors.Remove(director); + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Control/ControlPlayableAsset.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Control/ControlPlayableAsset.cs.meta new file mode 100644 index 0000000..3f4d090 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Control/ControlPlayableAsset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 48853ae485fa386428341ac1ea122570 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Control/ControlTrack.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Control/ControlTrack.cs new file mode 100644 index 0000000..e42c9af --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Control/ControlTrack.cs @@ -0,0 +1,14 @@ +using UnityEngine; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// A Track whose clips control time-related elements on a GameObject. + /// </summary> + [TrackClipType(typeof(ControlPlayableAsset), false)] + [ExcludeFromPreset] + public class ControlTrack : TrackAsset + { + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Control/ControlTrack.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Control/ControlTrack.cs.meta new file mode 100644 index 0000000..95582da --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Control/ControlTrack.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 15e0374501f39d54eb30235764636e0e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/DiscreteTime.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/DiscreteTime.cs new file mode 100644 index 0000000..af68af8 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/DiscreteTime.cs @@ -0,0 +1,226 @@ +using System; + +namespace UnityEngine.Timeline +{ + struct DiscreteTime : IComparable + { + const double k_Tick = 1e-12; + public static readonly DiscreteTime kMaxTime = new DiscreteTime(Int64.MaxValue); + + readonly Int64 m_DiscreteTime; + + public static double tickValue { get { return k_Tick; } } + + public DiscreteTime(DiscreteTime time) + { + m_DiscreteTime = time.m_DiscreteTime; + } + + DiscreteTime(Int64 time) + { + m_DiscreteTime = time; + } + + public DiscreteTime(double time) + { + m_DiscreteTime = DoubleToDiscreteTime(time); + } + + public DiscreteTime(float time) + { + m_DiscreteTime = FloatToDiscreteTime(time); + } + + public DiscreteTime(int time) + { + m_DiscreteTime = IntToDiscreteTime(time); + } + + public DiscreteTime(int frame, double fps) + { + m_DiscreteTime = DoubleToDiscreteTime(frame * fps); + } + + public DiscreteTime OneTickBefore() + { + return new DiscreteTime(m_DiscreteTime - 1); + } + + public DiscreteTime OneTickAfter() + { + return new DiscreteTime(m_DiscreteTime + 1); + } + + public Int64 GetTick() + { + return m_DiscreteTime; + } + + public static DiscreteTime FromTicks(Int64 ticks) + { + return new DiscreteTime(ticks); + } + + public int CompareTo(object obj) + { + if (obj is DiscreteTime) + return m_DiscreteTime.CompareTo(((DiscreteTime)obj).m_DiscreteTime); + return 1; + } + + public bool Equals(DiscreteTime other) + { + return m_DiscreteTime == other.m_DiscreteTime; + } + + public override bool Equals(object obj) + { + if (obj is DiscreteTime) + return Equals((DiscreteTime)obj); + return false; + } + + static Int64 DoubleToDiscreteTime(double time) + { + double number = (time / k_Tick) + 0.5; + if (number < Int64.MaxValue && number > Int64.MinValue) + return (Int64)number; + throw new ArgumentOutOfRangeException("Time is over the discrete range."); + } + + static Int64 FloatToDiscreteTime(float time) + { + float number = (time / (float)k_Tick) + 0.5f; + if (number < Int64.MaxValue && number > Int64.MinValue) + return (Int64)number; + throw new ArgumentOutOfRangeException("Time is over the discrete range."); + } + + static Int64 IntToDiscreteTime(int time) + { + return DoubleToDiscreteTime(time); + } + + static double ToDouble(Int64 time) + { + return time * k_Tick; + } + + static float ToFloat(Int64 time) + { + return (float)ToDouble(time); + } + + public static explicit operator double(DiscreteTime b) + { + return ToDouble(b.m_DiscreteTime); + } + + public static explicit operator float(DiscreteTime b) + { + return ToFloat(b.m_DiscreteTime); + } + + public static explicit operator Int64(DiscreteTime b) + { + return b.m_DiscreteTime; + } + + public static explicit operator DiscreteTime(double time) + { + return new DiscreteTime(time); + } + + public static explicit operator DiscreteTime(float time) + { + return new DiscreteTime(time); + } + + public static implicit operator DiscreteTime(Int32 time) + { + return new DiscreteTime(time); + } + + public static explicit operator DiscreteTime(Int64 time) + { + return new DiscreteTime(time); + } + + public static bool operator==(DiscreteTime lhs, DiscreteTime rhs) + { + return lhs.m_DiscreteTime == rhs.m_DiscreteTime; + } + + public static bool operator!=(DiscreteTime lhs, DiscreteTime rhs) + { + return !(lhs == rhs); + } + + public static bool operator>(DiscreteTime lhs, DiscreteTime rhs) + { + return lhs.m_DiscreteTime > rhs.m_DiscreteTime; + } + + public static bool operator<(DiscreteTime lhs, DiscreteTime rhs) + { + return lhs.m_DiscreteTime < rhs.m_DiscreteTime; + } + + public static bool operator<=(DiscreteTime lhs, DiscreteTime rhs) + { + return lhs.m_DiscreteTime <= rhs.m_DiscreteTime; + } + + public static bool operator>=(DiscreteTime lhs, DiscreteTime rhs) + { + return lhs.m_DiscreteTime >= rhs.m_DiscreteTime; + } + + public static DiscreteTime operator+(DiscreteTime lhs, DiscreteTime rhs) + { + return new DiscreteTime(lhs.m_DiscreteTime + rhs.m_DiscreteTime); + } + + public static DiscreteTime operator-(DiscreteTime lhs, DiscreteTime rhs) + { + return new DiscreteTime(lhs.m_DiscreteTime - rhs.m_DiscreteTime); + } + + public override string ToString() + { + return m_DiscreteTime.ToString(); + } + + public override int GetHashCode() + { + return m_DiscreteTime.GetHashCode(); + } + + public static DiscreteTime Min(DiscreteTime lhs, DiscreteTime rhs) + { + return new DiscreteTime(Math.Min(lhs.m_DiscreteTime, rhs.m_DiscreteTime)); + } + + public static DiscreteTime Max(DiscreteTime lhs, DiscreteTime rhs) + { + return new DiscreteTime(Math.Max(lhs.m_DiscreteTime, rhs.m_DiscreteTime)); + } + + public static double SnapToNearestTick(double time) + { + Int64 discreteTime = DoubleToDiscreteTime(time); + return ToDouble(discreteTime); + } + + public static float SnapToNearestTick(float time) + { + Int64 discreteTime = FloatToDiscreteTime(time); + return ToFloat(discreteTime); + } + + public static Int64 GetNearestTick(double time) + { + return DoubleToDiscreteTime(time); + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/DiscreteTime.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/DiscreteTime.cs.meta new file mode 100644 index 0000000..e6d4977 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/DiscreteTime.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8beed9aab74505d488e6befe54c3f6ef +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation.meta new file mode 100644 index 0000000..433d36b --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4c6f60d349ea37048af03504fc872f33 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/InfiniteRuntimeClip.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/InfiniteRuntimeClip.cs new file mode 100644 index 0000000..e833fd5 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/InfiniteRuntimeClip.cs @@ -0,0 +1,46 @@ +using System; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// Runtime clip customized for 'infinite' tracks playables. + /// Used for clips whose time needs to match the timelines exactly + /// </summary> + class InfiniteRuntimeClip : RuntimeElement + { + private Playable m_Playable; + private static readonly Int64 kIntervalEnd = DiscreteTime.GetNearestTick(TimelineClip.kMaxTimeValue); + + public InfiniteRuntimeClip(Playable playable) + { + m_Playable = playable; + } + + public override Int64 intervalStart + { + get { return 0; } + } + + public override Int64 intervalEnd + { + get { return kIntervalEnd; } + } + + public override bool enable + { + set + { + if (value) + m_Playable.Play(); + else + m_Playable.Pause(); + } + } + + public override void EvaluateAt(double localTime, FrameData frameData) + { + m_Playable.SetTime(localTime); + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/InfiniteRuntimeClip.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/InfiniteRuntimeClip.cs.meta new file mode 100644 index 0000000..c0451a6 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/InfiniteRuntimeClip.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9b5abcb38bac0c54794ad732a3fa0de3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/IntervalTree.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/IntervalTree.cs new file mode 100644 index 0000000..691f477 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/IntervalTree.cs @@ -0,0 +1,271 @@ +using System; +using System.Collections.Generic; + +namespace UnityEngine.Timeline +{ + interface IInterval + { + Int64 intervalStart { get; } + Int64 intervalEnd { get; } + } + + struct IntervalTreeNode // interval node, + { + public Int64 center; // midpoint for this node + public int first; // index of first element of this node in m_Entries + public int last; // index of the last element of this node in m_Entries + public int left; // index in m_Nodes of the left subnode + public int right; // index in m_Nodes of the right subnode + } + + class IntervalTree<T> where T : IInterval + { + internal struct Entry + { + public Int64 intervalStart; + public Int64 intervalEnd; + public T item; + } + + const int kMinNodeSize = 10; // the minimum number of entries to have subnodes + const int kInvalidNode = -1; + const Int64 kCenterUnknown = Int64.MaxValue; // center hasn't been calculated. indicates no children + + readonly List<Entry> m_Entries = new List<Entry>(); + readonly List<IntervalTreeNode> m_Nodes = new List<IntervalTreeNode>(); + + /// <summary> + /// Whether the tree will be rebuilt on the next query + /// </summary> + public bool dirty { get; internal set; } + + /// <summary> + /// Add an IInterval to the tree + /// </summary> + public void Add(T item) + { + if (item == null) + return; + + m_Entries.Add( + new Entry() + { + intervalStart = item.intervalStart, + intervalEnd = item.intervalEnd, + item = item + } + ); + dirty = true; + } + + /// <summary> + /// Query the tree at a particular time + /// </summary> + /// <param name="value"></param> + /// <param name="results"></param> + public void IntersectsWith(Int64 value, List<T> results) + { + if (m_Entries.Count == 0) + return; + + if (dirty) + { + Rebuild(); + dirty = false; + } + + if (m_Nodes.Count > 0) + Query(m_Nodes[0], value, results); + } + + /// <summary> + /// Query the tree at a particular range of time + /// </summary> + /// <param name="start"></param> + /// <param name="end"></param> + /// <param name="results"></param> + public void IntersectsWithRange(Int64 start, Int64 end, List<T> results) + { + if (start > end) + return; + + if (m_Entries.Count == 0) + return; + + if (dirty) + { + Rebuild(); + dirty = false; + } + + if (m_Nodes.Count > 0) + QueryRange(m_Nodes[0], start, end, results); + } + + /// <summary> + /// Updates the intervals from their source. Use this to detect if the data in the tree + /// has changed. + /// </summary> + public void UpdateIntervals() + { + bool isDirty = false; + for (int i = 0; i < m_Entries.Count; i++) + { + var n = m_Entries[i]; + var s = n.item.intervalStart; + var e = n.item.intervalEnd; + + isDirty |= n.intervalStart != s; + isDirty |= n.intervalEnd != e; + + m_Entries[i] = new Entry() + { + intervalStart = s, + intervalEnd = e, + item = n.item + }; + } + + dirty |= isDirty; + } + + private void Query(IntervalTreeNode intervalTreeNode, Int64 value, List<T> results) + { + for (int i = intervalTreeNode.first; i <= intervalTreeNode.last; i++) + { + var entry = m_Entries[i]; + if (value >= entry.intervalStart && value < entry.intervalEnd) + { + results.Add(entry.item); + } + } + + if (intervalTreeNode.center == kCenterUnknown) + return; + if (intervalTreeNode.left != kInvalidNode && value < intervalTreeNode.center) + Query(m_Nodes[intervalTreeNode.left], value, results); + if (intervalTreeNode.right != kInvalidNode && value > intervalTreeNode.center) + Query(m_Nodes[intervalTreeNode.right], value, results); + } + + private void QueryRange(IntervalTreeNode intervalTreeNode, Int64 start, Int64 end, List<T> results) + { + for (int i = intervalTreeNode.first; i <= intervalTreeNode.last; i++) + { + var entry = m_Entries[i]; + if (end >= entry.intervalStart && start < entry.intervalEnd) + { + results.Add(entry.item); + } + } + + if (intervalTreeNode.center == kCenterUnknown) + return; + if (intervalTreeNode.left != kInvalidNode && start < intervalTreeNode.center) + QueryRange(m_Nodes[intervalTreeNode.left], start, end, results); + if (intervalTreeNode.right != kInvalidNode && end > intervalTreeNode.center) + QueryRange(m_Nodes[intervalTreeNode.right], start, end, results); + } + + private void Rebuild() + { + m_Nodes.Clear(); + m_Nodes.Capacity = m_Entries.Capacity; + Rebuild(0, m_Entries.Count - 1); + } + + private int Rebuild(int start, int end) + { + IntervalTreeNode intervalTreeNode = new IntervalTreeNode(); + + // minimum size, don't subdivide + int count = end - start + 1; + if (count < kMinNodeSize) + { + intervalTreeNode = new IntervalTreeNode() {center = kCenterUnknown, first = start, last = end, left = kInvalidNode, right = kInvalidNode}; + m_Nodes.Add(intervalTreeNode); + return m_Nodes.Count - 1; + } + + var min = Int64.MaxValue; + var max = Int64.MinValue; + + for (int i = start; i <= end; i++) + { + var o = m_Entries[i]; + min = Math.Min(min, o.intervalStart); + max = Math.Max(max, o.intervalEnd); + } + + var center = (max + min) / 2; + intervalTreeNode.center = center; + + // first pass, put every thing left of center, left + int x = start; + int y = end; + while (true) + { + while (x <= end && m_Entries[x].intervalEnd < center) + x++; + + while (y >= start && m_Entries[y].intervalEnd >= center) + y--; + + if (x > y) + break; + + var nodeX = m_Entries[x]; + var nodeY = m_Entries[y]; + + m_Entries[y] = nodeX; + m_Entries[x] = nodeY; + } + + intervalTreeNode.first = x; + + // second pass, put every start passed the center right + y = end; + while (true) + { + while (x <= end && m_Entries[x].intervalStart <= center) + x++; + + while (y >= start && m_Entries[y].intervalStart > center) + y--; + + if (x > y) + break; + + var nodeX = m_Entries[x]; + var nodeY = m_Entries[y]; + + m_Entries[y] = nodeX; + m_Entries[x] = nodeY; + } + + intervalTreeNode.last = y; + + // reserve a place + m_Nodes.Add(new IntervalTreeNode()); + int index = m_Nodes.Count - 1; + + intervalTreeNode.left = kInvalidNode; + intervalTreeNode.right = kInvalidNode; + + if (start < intervalTreeNode.first) + intervalTreeNode.left = Rebuild(start, intervalTreeNode.first - 1); + + if (end > intervalTreeNode.last) + intervalTreeNode.right = Rebuild(intervalTreeNode.last + 1, end); + + m_Nodes[index] = intervalTreeNode; + return index; + } + + public void Clear() + { + m_Entries.Clear(); + m_Nodes.Clear(); + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/IntervalTree.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/IntervalTree.cs.meta new file mode 100644 index 0000000..cf954ab --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/IntervalTree.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8f74c99a65464bb4b86ccb314ee95a7f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/RuntimeClip.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/RuntimeClip.cs new file mode 100644 index 0000000..9b260cd --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/RuntimeClip.cs @@ -0,0 +1,110 @@ +using UnityEngine; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + // The RuntimeClip wraps a single clip in an instantiated sequence. + // It supports the IInterval interface so that it can be stored in the interval tree + // It is this class that is returned by an interval tree query. + class RuntimeClip : RuntimeClipBase + { + TimelineClip m_Clip; + Playable m_Playable; + Playable m_ParentMixer; + + public override double start + { + get { return m_Clip.extrapolatedStart; } + } + + public override double duration + { + get { return m_Clip.extrapolatedDuration; } + } + + public RuntimeClip(TimelineClip clip, Playable clipPlayable, Playable parentMixer) + { + Create(clip, clipPlayable, parentMixer); + } + + void Create(TimelineClip clip, Playable clipPlayable, Playable parentMixer) + { + m_Clip = clip; + m_Playable = clipPlayable; + m_ParentMixer = parentMixer; + clipPlayable.Pause(); + } + + public TimelineClip clip + { + get { return m_Clip; } + } + + public Playable mixer + { + get { return m_ParentMixer; } + } + + public Playable playable + { + get { return m_Playable; } + } + + public override bool enable + { + set + { + if (value && m_Playable.GetPlayState() != PlayState.Playing) + { + m_Playable.Play(); + SetTime(m_Clip.clipIn); + } + else if (!value && m_Playable.GetPlayState() != PlayState.Paused) + { + m_Playable.Pause(); + if (m_ParentMixer.IsValid()) + m_ParentMixer.SetInputWeight(m_Playable, 0.0f); + } + } + } + + public void SetTime(double time) + { + m_Playable.SetTime(time); + } + + public void SetDuration(double duration) + { + m_Playable.SetDuration(duration); + } + + public override void EvaluateAt(double localTime, FrameData frameData) + { + enable = true; + + float weight = 1.0f; + if (clip.IsPreExtrapolatedTime(localTime)) + weight = clip.EvaluateMixIn((float)clip.start); + else if (clip.IsPostExtrapolatedTime(localTime)) + weight = clip.EvaluateMixOut((float)clip.end); + else + weight = clip.EvaluateMixIn(localTime) * clip.EvaluateMixOut(localTime); + + if (mixer.IsValid()) + mixer.SetInputWeight(playable, weight); + + // localTime of the sequence to localtime of the clip + double clipTime = clip.ToLocalTime(localTime); + if (clipTime.CompareTo(0.0) >= 0) + { + SetTime(clipTime); + } + SetDuration(clip.extrapolatedDuration); + } + + public override void Reset() + { + SetTime(m_Clip.clipIn); + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/RuntimeClip.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/RuntimeClip.cs.meta new file mode 100644 index 0000000..3ae5d53 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/RuntimeClip.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 70a190a1b304d1e43995af35d09231d6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/RuntimeClipBase.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/RuntimeClipBase.cs new file mode 100644 index 0000000..f6a178a --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/RuntimeClipBase.cs @@ -0,0 +1,21 @@ +using System; +using UnityEngine; + +namespace UnityEngine.Timeline +{ + internal abstract class RuntimeClipBase : RuntimeElement + { + public abstract double start { get; } + public abstract double duration { get; } + + public override Int64 intervalStart + { + get { return DiscreteTime.GetNearestTick(start); } + } + + public override Int64 intervalEnd + { + get { return DiscreteTime.GetNearestTick(start + duration); } + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/RuntimeClipBase.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/RuntimeClipBase.cs.meta new file mode 100644 index 0000000..49f3b62 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/RuntimeClipBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 70f955bbb437a494888ef54d97abb474 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/RuntimeElement.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/RuntimeElement.cs new file mode 100644 index 0000000..bdd7f11 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/RuntimeElement.cs @@ -0,0 +1,17 @@ +using System; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + abstract class RuntimeElement : IInterval + { + public abstract Int64 intervalStart { get; } + public abstract Int64 intervalEnd { get; } + public int intervalBit { get; set; } + + public abstract bool enable { set; } + public abstract void EvaluateAt(double localTime, FrameData frameData); + + public virtual void Reset() {} + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/RuntimeElement.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/RuntimeElement.cs.meta new file mode 100644 index 0000000..03b8737 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/RuntimeElement.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 76b6bf32a6fcf934aab8c529bddccc81 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/ScheduleRuntimeClip.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/ScheduleRuntimeClip.cs new file mode 100644 index 0000000..4831cc4 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/ScheduleRuntimeClip.cs @@ -0,0 +1,111 @@ +using System; +using UnityEngine; +using UnityEngine.Audio; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + // Special runtime clip implementation that handles playables that use a scheduling system + // such as Audio + internal class ScheduleRuntimeClip : RuntimeClipBase + { + private TimelineClip m_Clip; + private Playable m_Playable; + private Playable m_ParentMixer; + private double m_StartDelay; + private double m_FinishTail; + private bool m_Started = false; + + // represents the start point when we want to start getting updated + public override double start + { + get { return Math.Max(0, m_Clip.start - m_StartDelay); } + } + + public override double duration + { + get { return m_Clip.duration + m_FinishTail + m_Clip.start - start; } + } + + public void SetTime(double time) + { + m_Playable.SetTime(time); + } + + public TimelineClip clip { get { return m_Clip; } } + public Playable mixer { get { return m_ParentMixer; } } + public Playable playable { get { return m_Playable; } } + + public ScheduleRuntimeClip(TimelineClip clip, Playable clipPlayable, + Playable parentMixer, double startDelay = 0.2, double finishTail = 0.1) + { + Create(clip, clipPlayable, parentMixer, startDelay, finishTail); + } + + private void Create(TimelineClip clip, Playable clipPlayable, Playable parentMixer, + double startDelay, double finishTail) + { + m_Clip = clip; + m_Playable = clipPlayable; + m_ParentMixer = parentMixer; + m_StartDelay = startDelay; + m_FinishTail = finishTail; + clipPlayable.Pause(); + } + + public override bool enable + { + set + { + if (value && m_Playable.GetPlayState() != PlayState.Playing) + { + m_Playable.Play(); + } + else if (!value && m_Playable.GetPlayState() != PlayState.Paused) + { + m_Playable.Pause(); + if (m_ParentMixer.IsValid()) + m_ParentMixer.SetInputWeight(m_Playable, 0.0f); + } + + m_Started &= value; + } + } + + public override void EvaluateAt(double localTime, FrameData frameData) + { + if (frameData.timeHeld) + { + enable = false; + return; + } + + + bool forceSeek = frameData.seekOccurred || frameData.timeLooped || frameData.evaluationType == FrameData.EvaluationType.Evaluate; + + // If we are in the tail region of the clip, then dont do anything + if (localTime > start + duration - m_FinishTail) + return; + + // this may set the weight to 1 in a delay, but it will avoid missing the start + float weight = clip.EvaluateMixIn(localTime) * clip.EvaluateMixOut(localTime); + if (mixer.IsValid()) + mixer.SetInputWeight(playable, weight); + + // localTime of the sequence to localtime of the clip + if (!m_Started || forceSeek) + { + // accounts for clip in and speed + double clipTime = clip.ToLocalTime(Math.Max(localTime, clip.start)); + // multiply by the time scale so the delay is local to the clip + // Audio will rescale based on it's effective time scale (which includes the parent) + double startDelay = Math.Max(clip.start - localTime, 0) * clip.timeScale; + double durationLocal = m_Clip.duration * clip.timeScale; + if (m_Playable.IsPlayableOfType<AudioClipPlayable>()) + ((AudioClipPlayable)m_Playable).Seek(clipTime, startDelay, durationLocal); + + m_Started = true; + } + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/ScheduleRuntimeClip.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/ScheduleRuntimeClip.cs.meta new file mode 100644 index 0000000..b3ea114 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/ScheduleRuntimeClip.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b250be9db55288b48ac121c074d795e6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events.meta new file mode 100644 index 0000000..847f9d1 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b8c5993172f27e4419d7d4ed5ef77840 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/IMarker.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/IMarker.cs new file mode 100644 index 0000000..2595cdf --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/IMarker.cs @@ -0,0 +1,31 @@ +namespace UnityEngine.Timeline +{ + /// <summary> + /// Interface implemented by markers. + /// </summary> + /// <remarks> + /// A marker is a point in time. + /// </remarks> + /// <seealso cref="UnityEngine.Timeline.Marker"/> + public interface IMarker + { + /// <summary> + /// The time set for the marker, in seconds. + /// </summary> + double time { get; set; } + + /// <summary> + /// The track that contains the marker. + /// </summary> + TrackAsset parent { get; } + + /// <summary> + /// This method is called when the marker is initialized. + /// </summary> + /// <param name="parent">The track that contains the marker.</param> + /// <remarks> + /// This method is called after each deserialization of the Timeline Asset. + /// </remarks> + void Initialize(TrackAsset parent); + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/IMarker.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/IMarker.cs.meta new file mode 100644 index 0000000..3869cbc --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/IMarker.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4cb169caa67eddf4d83b39fd0917a945 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/INotificationOptionProvider.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/INotificationOptionProvider.cs new file mode 100644 index 0000000..7a23d7d --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/INotificationOptionProvider.cs @@ -0,0 +1,15 @@ +namespace UnityEngine.Timeline +{ + /// <summary> + /// Implement this interface to change the behaviour of an INotification. + /// </summary> + /// This interface must be implemented along with <see cref="UnityEngine.Playables.INotification"/> to modify the default behaviour of a notification. + /// <seealso cref="UnityEngine.Timeline.NotificationFlags"/> + public interface INotificationOptionProvider + { + /// <summary> + /// The flags that change the triggering behaviour. + /// </summary> + NotificationFlags flags { get; } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/INotificationOptionProvider.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/INotificationOptionProvider.cs.meta new file mode 100644 index 0000000..3e59b72 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/INotificationOptionProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5082cb99a8f99b84d84dd8b4c5233a9e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Marker.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Marker.cs new file mode 100644 index 0000000..2f12cd7 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Marker.cs @@ -0,0 +1,53 @@ +using System; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// Use Marker as a base class when creating a custom marker. + /// </summary> + /// <remarks> + /// A marker is a point in time. + /// </remarks> + public abstract class Marker : ScriptableObject, IMarker + { + [SerializeField, TimeField, Tooltip("Time for the marker")] double m_Time; + + /// <inheritdoc/> + public TrackAsset parent { get; private set; } + + /// <inheritdoc/> + /// <remarks> + /// The marker time cannot be negative. + /// </remarks> + public double time + { + get { return m_Time; } + set { m_Time = Math.Max(value, 0); } + } + + void IMarker.Initialize(TrackAsset parentTrack) + { + // We only really want to update the parent when the object is first deserialized + // If not a cloned track would "steal" the source's markers + if (parent == null) + { + parent = parentTrack; + try + { + OnInitialize(parentTrack); + } + catch (Exception e) + { + Debug.LogError(e.Message, this); + } + } + } + + /// <summary> + /// Override this method to receive a callback when the marker is initialized. + /// </summary> + public virtual void OnInitialize(TrackAsset aPent) + { + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Marker.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Marker.cs.meta new file mode 100644 index 0000000..2bb36b5 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Marker.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 89b48a03f6f43e94e87cc8d2104d3d4d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/MarkerList.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/MarkerList.cs new file mode 100644 index 0000000..4be4fc2 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/MarkerList.cs @@ -0,0 +1,168 @@ +using System; +using System.Collections.Generic; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + [Serializable] + struct MarkerList : ISerializationCallbackReceiver + { + [SerializeField, HideInInspector] List<ScriptableObject> m_Objects; + + [HideInInspector, NonSerialized] List<IMarker> m_Cache; + bool m_CacheDirty; + bool m_HasNotifications; + public List<IMarker> markers + { + get + { + BuildCache(); + return m_Cache; + } + } + + public MarkerList(int capacity) + { + m_Objects = new List<ScriptableObject>(capacity); + m_Cache = new List<IMarker>(capacity); + m_CacheDirty = true; + m_HasNotifications = false; + } + + public void Add(ScriptableObject item) + { + if (item == null) + return; + + m_Objects.Add(item); + m_CacheDirty = true; + } + + public bool Remove(IMarker item) + { + if (!(item is ScriptableObject)) + throw new InvalidOperationException("Supplied type must be a ScriptableObject"); + return Remove((ScriptableObject)item, item.parent.timelineAsset, item.parent); + } + + public bool Remove(ScriptableObject item, TimelineAsset timelineAsset, PlayableAsset thingToDirty) + { + if (!m_Objects.Contains(item)) return false; + + TimelineUndo.PushUndo(thingToDirty, "Delete Marker"); + m_Objects.Remove(item); + m_CacheDirty = true; + TimelineUndo.PushDestroyUndo(timelineAsset, thingToDirty, item, "Delete Marker"); + return true; + } + + public void Clear() + { + m_Objects.Clear(); + m_CacheDirty = true; + } + + public bool Contains(ScriptableObject item) + { + return m_Objects.Contains(item); + } + + public IEnumerable<IMarker> GetMarkers() + { + return markers; + } + + public int Count + { + get { return markers.Count; } + } + + public IMarker this[int idx] + { + get + { + return markers[idx]; + } + } + + public List<ScriptableObject> GetRawMarkerList() + { + return m_Objects; + } + + public IMarker CreateMarker(Type type, double time, TrackAsset owner) + { + if (!typeof(ScriptableObject).IsAssignableFrom(type) || !typeof(IMarker).IsAssignableFrom(type)) + { + throw new InvalidOperationException( + "The requested type needs to inherit from ScriptableObject and implement IMarker"); + } + if (!owner.supportsNotifications && typeof(INotification).IsAssignableFrom(type)) + { + throw new InvalidOperationException( + "Markers implementing the INotification interface cannot be added on tracks that do not support notifications"); + } + + var markerSO = ScriptableObject.CreateInstance(type); + var marker = (IMarker)markerSO; + marker.time = time; + + TimelineCreateUtilities.SaveAssetIntoObject(markerSO, owner); + TimelineUndo.RegisterCreatedObjectUndo(markerSO, "Create " + type.Name); + TimelineUndo.PushUndo(owner, "Create " + type.Name); + + Add(markerSO); + marker.Initialize(owner); + + return marker; + } + + public bool HasNotifications() + { + BuildCache(); + return m_HasNotifications; + } + + void ISerializationCallbackReceiver.OnBeforeSerialize() + { + } + + void ISerializationCallbackReceiver.OnAfterDeserialize() + { +#if UNITY_EDITOR + for (int i = m_Objects.Count - 1; i >= 0; i--) + { + object o = m_Objects[i]; + if (o == null) + { + Debug.LogWarning("Empty marker found while loading timeline. It will be removed."); + m_Objects.RemoveAt(i); + } + } +#endif + m_CacheDirty = true; + } + + void BuildCache() + { + if (m_CacheDirty) + { + m_Cache = new List<IMarker>(m_Objects.Count); + m_HasNotifications = false; + foreach (var o in m_Objects) + { + if (o != null) + { + m_Cache.Add(o as IMarker); + if (o is INotification) + { + m_HasNotifications = true; + } + } + } + + m_CacheDirty = false; + } + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/MarkerList.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/MarkerList.cs.meta new file mode 100644 index 0000000..1875712 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/MarkerList.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4335a164bb763104c8805212c23d795f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/MarkerTrack.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/MarkerTrack.cs new file mode 100644 index 0000000..f64b483 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/MarkerTrack.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + /// <inheritdoc /> + /// <summary> + /// Use this track to add Markers bound to a GameObject. + /// </summary> + [Serializable] + [TrackBindingType(typeof(GameObject))] + [HideInMenu] + [ExcludeFromPreset] + public class MarkerTrack : TrackAsset + { + /// <inheritdoc/> + public override IEnumerable<PlayableBinding> outputs + { + get + { + return this == timelineAsset.markerTrack ? + new List<PlayableBinding> {ScriptPlayableBinding.Create(name, null, typeof(GameObject))} : + base.outputs; + } + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/MarkerTrack.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/MarkerTrack.cs.meta new file mode 100644 index 0000000..37ca389 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/MarkerTrack.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2a16748d9461eae46a725db9776d5390 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/SignalTrack.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/SignalTrack.cs new file mode 100644 index 0000000..7c7bc4e --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/SignalTrack.cs @@ -0,0 +1,19 @@ +using System; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// Use this track to emit signals to a bound SignalReceiver. + /// </summary> + /// <remarks> + /// This track cannot contain clips. + /// </remarks> + /// <seealso cref="UnityEngine.Timeline.SignalEmitter"/> + /// <seealso cref="UnityEngine.Timeline.SignalReceiver"/> + /// <seealso cref="UnityEngine.Timeline.SignalAsset"/> + [Serializable] + [TrackBindingType(typeof(SignalReceiver))] + [TrackColor(0.25f, 0.25f, 0.25f)] + [ExcludeFromPreset] + public class SignalTrack : MarkerTrack {} +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/SignalTrack.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/SignalTrack.cs.meta new file mode 100644 index 0000000..3343f84 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/SignalTrack.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b46e36075dd1c124a8422c228e75e1fb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals.meta new file mode 100644 index 0000000..aa956e4 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5b00473355622524394628f7ec51808d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals/CustomSignalEventDrawer.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals/CustomSignalEventDrawer.cs new file mode 100644 index 0000000..49df674 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals/CustomSignalEventDrawer.cs @@ -0,0 +1,5 @@ +namespace UnityEngine.Timeline +{ + //used to tell Signal Handler inspector to use a special drawer for UnityEvent + class CustomSignalEventDrawer : PropertyAttribute {} +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals/CustomSignalEventDrawer.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals/CustomSignalEventDrawer.cs.meta new file mode 100644 index 0000000..c7c813f --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals/CustomSignalEventDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a7ebd1239373d5f41af65ef32d67f445 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals/SignalAsset.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals/SignalAsset.cs new file mode 100644 index 0000000..d605588 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals/SignalAsset.cs @@ -0,0 +1,22 @@ +using System; +using UnityEngine; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// An asset representing an emitted signal. A SignalAsset connects a SignalEmitter with a SignalReceiver. + /// </summary> + /// <seealso cref="UnityEngine.Timeline.SignalEmitter"/> + /// <seealso cref="UnityEngine.Timeline.SignalReceiver"/> + [AssetFileNameExtension("signal")] + public class SignalAsset : ScriptableObject + { + internal static event Action<SignalAsset> OnEnableCallback; + + void OnEnable() + { + if (OnEnableCallback != null) + OnEnableCallback(this); + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals/SignalAsset.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals/SignalAsset.cs.meta new file mode 100644 index 0000000..437f4d3 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals/SignalAsset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d6fa2d92fc1b3f34da284357edf89c3b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals/SignalEmitter.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals/SignalEmitter.cs new file mode 100644 index 0000000..d4d4ca9 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals/SignalEmitter.cs @@ -0,0 +1,72 @@ +using System; +using UnityEngine; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + /// <inheritdoc cref="UnityEngine.Timeline.IMarker" /> + /// <summary> + /// Marker that emits a signal to a SignalReceiver. + /// </summary> + /// A SignalEmitter emits a notification through the playable system. A SignalEmitter is used with a SignalReceiver and a SignalAsset. + /// <seealso cref="UnityEngine.Timeline.SignalAsset"/> + /// <seealso cref="UnityEngine.Timeline.SignalReceiver"/> + [Serializable] + [CustomStyle("SignalEmitter")] + [ExcludeFromPreset] + public class SignalEmitter : Marker, INotification, INotificationOptionProvider + { + [SerializeField] bool m_Retroactive; + [SerializeField] bool m_EmitOnce; + [SerializeField] SignalAsset m_Asset; + + /// <summary> + /// Use retroactive to emit the signal if playback starts after the SignalEmitter time. + /// </summary> + public bool retroactive + { + get { return m_Retroactive; } + set { m_Retroactive = value; } + } + + /// <summary> + /// Use emitOnce to emit this signal once during loops. + /// </summary> + public bool emitOnce + { + get { return m_EmitOnce; } + set { m_EmitOnce = value; } + } + + /// <summary> + /// Asset representing the signal being emitted. + /// </summary> + public SignalAsset asset + { + get { return m_Asset; } + set { m_Asset = value; } + } + + PropertyName INotification.id + { + get + { + if (m_Asset != null) + { + return new PropertyName(m_Asset.name); + } + return new PropertyName(string.Empty); + } + } + + NotificationFlags INotificationOptionProvider.flags + { + get + { + return (retroactive ? NotificationFlags.Retroactive : default(NotificationFlags)) | + (emitOnce ? NotificationFlags.TriggerOnce : default(NotificationFlags)) | + NotificationFlags.TriggerInEditMode; + } + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals/SignalEmitter.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals/SignalEmitter.cs.meta new file mode 100644 index 0000000..f14c8a3 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals/SignalEmitter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 15c38f6fa1940124db1ab7f6fe7268d1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals/SignalReceiver.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals/SignalReceiver.cs new file mode 100644 index 0000000..4e7564a --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals/SignalReceiver.cs @@ -0,0 +1,248 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// Listens for emitted signals and reacts depending on its defined reactions. + /// </summary> + /// A SignalReceiver contains a list of reactions. Each reaction is bound to a SignalAsset. + /// When a SignalEmitter emits a signal, the SignalReceiver invokes the corresponding reaction. + /// <seealso cref="UnityEngine.Timeline.SignalEmitter"/> + /// <seealso cref="UnityEngine.Timeline.SignalAsset"/> + public class SignalReceiver : MonoBehaviour, INotificationReceiver + { + [SerializeField] + EventKeyValue m_Events = new EventKeyValue(); + + /// <summary> + /// Called when a notification is sent. + /// </summary> + public void OnNotify(Playable origin, INotification notification, object context) + { + var signal = notification as SignalEmitter; + if (signal != null && signal.asset != null) + { + UnityEvent evt; + if (m_Events.TryGetValue(signal.asset, out evt) && evt != null) + { + evt.Invoke(); + } + } + } + + /// <summary> + /// Defines a new reaction for a SignalAsset. + /// </summary> + /// <param name="asset">The SignalAsset for which the reaction is being defined.</param> + /// <param name="reaction">The UnityEvent that describes the reaction.</param> + /// <exception cref="ArgumentNullException">Thrown when the asset is null.</exception> + /// <exception cref="ArgumentException">Thrown when the SignalAsset is already registered with this receiver.</exception> + public void AddReaction(SignalAsset asset, UnityEvent reaction) + { + if (asset == null) + throw new ArgumentNullException("asset"); + + if (m_Events.signals.Contains(asset)) + throw new ArgumentException("SignalAsset already used."); + m_Events.Append(asset, reaction); + } + + /// <summary> + /// Appends a null SignalAsset with a reaction specified by the UnityEvent. + /// </summary> + /// <param name="reaction">The new reaction to be appended.</param> + /// <returns>The index of the appended reaction.</returns> + /// <remarks>Multiple null assets are valid.</remarks> + public int AddEmptyReaction(UnityEvent reaction) + { + m_Events.Append(null, reaction); + return m_Events.events.Count - 1; + } + + /// <summary> + /// Removes the first occurrence of a SignalAsset. + /// </summary> + /// <param name="asset">The SignalAsset to be removed.</param> + public void Remove(SignalAsset asset) + { + if (!m_Events.signals.Contains(asset)) + { + throw new ArgumentException("The SignalAsset is not registered with this receiver."); + } + + m_Events.Remove(asset); + } + + /// <summary> + /// Gets a list of all registered SignalAssets. + /// </summary> + /// <returns>Returns a list of SignalAssets.</returns> + public IEnumerable<SignalAsset> GetRegisteredSignals() + { + return m_Events.signals; + } + + /// <summary> + /// Gets the first UnityEvent associated with a SignalAsset. + /// </summary> + /// <param name="key">A SignalAsset defining the signal.</param> + /// <returns>Returns the reaction associated with a SignalAsset. Returns null if the signal asset does not exist.</returns> + public UnityEvent GetReaction(SignalAsset key) + { + UnityEvent ret; + if (m_Events.TryGetValue(key, out ret)) + { + return ret; + } + + return null; + } + + /// <summary> + /// Returns the count of registered SignalAssets. + /// </summary> + /// <returns></returns> + public int Count() + { + return m_Events.signals.Count; + } + + /// <summary> + /// Replaces the SignalAsset associated with a reaction at a specific index. + /// </summary> + /// <param name="idx">The index of the reaction.</param> + /// <param name="newKey">The replacement SignalAsset.</param> + /// <exception cref="ArgumentException">Thrown when the replacement SignalAsset is already registered to this SignalReceiver.</exception> + /// <remarks>The new SignalAsset can be null.</remarks> + public void ChangeSignalAtIndex(int idx, SignalAsset newKey) + { + if (idx < 0 || idx > m_Events.signals.Count - 1) + throw new IndexOutOfRangeException(); + + if (m_Events.signals[idx] == newKey) + return; + var alreadyUsed = m_Events.signals.Contains(newKey); + if (newKey == null || m_Events.signals[idx] == null || !alreadyUsed) + m_Events.signals[idx] = newKey; + + if (newKey != null && alreadyUsed) + throw new ArgumentException("SignalAsset already used."); + } + + /// <summary> + /// Removes the SignalAsset and reaction at a specific index. + /// </summary> + /// <param name="idx">The index of the SignalAsset to be removed.</param> + public void RemoveAtIndex(int idx) + { + if (idx < 0 || idx > m_Events.signals.Count - 1) + throw new IndexOutOfRangeException(); + m_Events.Remove(idx); + } + + /// <summary> + /// Replaces the reaction at a specific index with a new UnityEvent. + /// </summary> + /// <param name="idx">The index of the reaction to be replaced.</param> + /// <param name="reaction">The replacement reaction.</param> + /// <exception cref="ArgumentNullException">Thrown when the replacement reaction is null.</exception> + public void ChangeReactionAtIndex(int idx, UnityEvent reaction) + { + if (idx < 0 || idx > m_Events.events.Count - 1) + throw new IndexOutOfRangeException(); + + m_Events.events[idx] = reaction; + } + + /// <summary> + /// Gets the reaction at a specific index. + /// </summary> + /// <param name="idx">The index of the reaction.</param> + /// <returns>Returns a reaction.</returns> + public UnityEvent GetReactionAtIndex(int idx) + { + if (idx < 0 || idx > m_Events.events.Count - 1) + throw new IndexOutOfRangeException(); + return m_Events.events[idx]; + } + + /// <summary> + /// Gets the SignalAsset at a specific index + /// </summary> + /// <param name="idx">The index of the SignalAsset.</param> + /// <returns>Returns a SignalAsset.</returns> + public SignalAsset GetSignalAssetAtIndex(int idx) + { + if (idx < 0 || idx > m_Events.signals.Count - 1) + throw new IndexOutOfRangeException(); + return m_Events.signals[idx]; + } + + // Required by Unity for the MonoBehaviour to have an enabled state + private void OnEnable() + { + } + + [Serializable] + class EventKeyValue + { + [SerializeField] + List<SignalAsset> m_Signals = new List<SignalAsset>(); + + [SerializeField, CustomSignalEventDrawer] + List<UnityEvent> m_Events = new List<UnityEvent>(); + + public bool TryGetValue(SignalAsset key, out UnityEvent value) + { + var index = m_Signals.IndexOf(key); + if (index != -1) + { + value = m_Events[index]; + return true; + } + + value = null; + return false; + } + + public void Append(SignalAsset key, UnityEvent value) + { + m_Signals.Add(key); + m_Events.Add(value); + } + + public void Remove(int idx) + { + if (idx != -1) + { + m_Signals.RemoveAt(idx); + m_Events.RemoveAt(idx); + } + } + + public void Remove(SignalAsset key) + { + var idx = m_Signals.IndexOf(key); + if (idx != -1) + { + m_Signals.RemoveAt(idx); + m_Events.RemoveAt(idx); + } + } + + public List<SignalAsset> signals + { + get { return m_Signals; } + } + + public List<UnityEvent> events + { + get { return m_Events; } + } + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals/SignalReceiver.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals/SignalReceiver.cs.meta new file mode 100644 index 0000000..8d08ff6 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Events/Signals/SignalReceiver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e52de21a22b6dd44c9cc19f810c65059 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Extensions.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Extensions.meta new file mode 100644 index 0000000..d78ad19 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Extensions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6c61ba0c209bcc74f83e3650039ebdf9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Extensions/TrackExtensions.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Extensions/TrackExtensions.cs new file mode 100644 index 0000000..87eec1b --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Extensions/TrackExtensions.cs @@ -0,0 +1,76 @@ +using System; +using UnityEngine; +using UnityEngine.Timeline; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// Extension methods for TrackAssets + /// </summary> + public static class TrackAssetExtensions + { + /// <summary> + /// Gets the GroupTrack this track belongs to. + /// </summary> + /// <param name="asset">The track asset to find the group of</param> + /// <returns>The parent GroupTrack or null if the Track is an override track, or root track.</returns> + public static GroupTrack GetGroup(this TrackAsset asset) + { + if (asset == null) + return null; + + return asset.parent as GroupTrack; + } + + /// <summary> + /// Assigns the track to the specified group track. + /// </summary> + /// <param name="asset">The track to assign.</param> + /// <param name="group">The GroupTrack to assign the track to.</param> + /// <remarks> + /// Does not support assigning to a group in a different timeline. + /// </remarks> + public static void SetGroup(this TrackAsset asset, GroupTrack group) + { + const string undoString = "Reparent"; + + if (asset == null || asset == group || asset.parent == group) + return; + + if (group != null && asset.timelineAsset != group.timelineAsset) + throw new InvalidOperationException("Cannot assign to a group in a different timeline"); + + + TimelineUndo.PushUndo(asset, undoString); + + var timeline = asset.timelineAsset; + var parentTrack = asset.parent as TrackAsset; + var parentTimeline = asset.parent as TimelineAsset; + if (parentTrack != null || parentTimeline != null) + { + TimelineUndo.PushUndo(asset.parent, undoString); + if (parentTimeline != null) + { + parentTimeline.RemoveTrack(asset); + } + else + { + parentTrack.RemoveSubTrack(asset); + } + } + + if (group == null) + { + TimelineUndo.PushUndo(timeline, undoString); + asset.parent = asset.timelineAsset; + timeline.AddTrackInternal(asset); + } + else + { + TimelineUndo.PushUndo(group, undoString); + group.AddChild(asset); + } + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Extensions/TrackExtensions.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Extensions/TrackExtensions.cs.meta new file mode 100644 index 0000000..823e94a --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Extensions/TrackExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d3721d5c6afa8e545995dfaada328476 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/GroupTrack.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/GroupTrack.cs new file mode 100644 index 0000000..a6d8a7d --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/GroupTrack.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// A group track is a container that allows tracks to be arranged in a hierarchical manner. + /// </summary> + [Serializable] + [TrackClipType(typeof(TrackAsset))] + [SupportsChildTracks] + public class GroupTrack : TrackAsset + { + internal override bool CanCompileClips() + { + return false; + } + + /// <inheritdoc /> + public override IEnumerable<PlayableBinding> outputs + { + get { return PlayableBinding.None; } + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/GroupTrack.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/GroupTrack.cs.meta new file mode 100644 index 0000000..89aac74 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/GroupTrack.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d0fc6f5187a81dc47999eefade6f0935 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/ILayerable.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/ILayerable.cs new file mode 100644 index 0000000..ff7d0e4 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/ILayerable.cs @@ -0,0 +1,20 @@ +using UnityEngine; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// Implement this interface on a TrackAsset derived class to support layers + /// </summary> + public interface ILayerable + { + /// <summary> + /// Creates a mixer that blends track mixers. + /// </summary> + /// <param name="graph">The graph where the mixer playable will be added.</param> + /// <param name="go">The GameObject that requested the graph.</param> + /// <param name="inputCount">The number of inputs on the mixer. There should be an input for each playable from each clip.</param> + /// <returns>Returns a playable that is used as a mixer. If this method returns Playable.Null, it indicates that a layer mixer is not needed. In this case, a single track mixer blends all playables generated from all layers.</returns> + Playable CreateLayerMixer(PlayableGraph graph, GameObject go, int inputCount); + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/ILayerable.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/ILayerable.cs.meta new file mode 100644 index 0000000..b585e7e --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/ILayerable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1dc9fdfe61a6a8749a0f6b89b45e887d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables.meta new file mode 100644 index 0000000..a162894 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8b7d06780fca6fc4384580d3ebed9219 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/ActivationControlPlayable.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/ActivationControlPlayable.cs new file mode 100644 index 0000000..3efb818 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/ActivationControlPlayable.cs @@ -0,0 +1,140 @@ +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// Playable that controls the active state of a GameObject. + /// </summary> + public class ActivationControlPlayable : PlayableBehaviour + { + /// <summary> + /// The state of a GameObject's activeness when a PlayableGraph stops. + /// </summary> + public enum PostPlaybackState + { + /// <summary> + /// Set the GameObject to active when the PlayableGraph stops. + /// </summary> + Active, + + /// <summary> + /// Set the GameObject to inactive when the [[PlayableGraph]] stops. + /// </summary> + Inactive, + + /// <summary> + /// Revert the GameObject to the active state it was before the [[PlayableGraph]] started. + /// </summary> + Revert + } + + enum InitialState + { + Unset, + Active, + Inactive + } + + public GameObject gameObject = null; + public PostPlaybackState postPlayback = PostPlaybackState.Revert; + InitialState m_InitialState; + + /// <summary> + /// Creates a ScriptPlayable with an ActivationControlPlayable behaviour attached + /// </summary> + /// <param name="graph">PlayableGraph that will own the playable</param> + /// <param name="gameObject">The GameObject that triggered the graph build</param> + /// <param name="postPlaybackState">The state to leave the gameObject after the graph is stopped</param> + /// <returns>Returns a playable that controls activation of a game object</returns> + public static ScriptPlayable<ActivationControlPlayable> Create(PlayableGraph graph, GameObject gameObject, ActivationControlPlayable.PostPlaybackState postPlaybackState) + { + if (gameObject == null) + return ScriptPlayable<ActivationControlPlayable>.Null; + + var handle = ScriptPlayable<ActivationControlPlayable>.Create(graph); + var playable = handle.GetBehaviour(); + playable.gameObject = gameObject; + playable.postPlayback = postPlaybackState; + + return handle; + } + + /// <summary> + /// This function is called when the Playable play state is changed to Playables.PlayState.Playing. + /// </summary> + /// <param name="playable">The playable this behaviour is attached to.</param> + /// <param name="info">The information about this frame</param> + public override void OnBehaviourPlay(Playable playable, FrameData info) + { + if (gameObject == null) + return; + + gameObject.SetActive(true); + } + + /// <summary> + /// This function is called when the Playable play state is changed to PlayState.Paused. + /// </summary> + /// <param name="playable">The playable this behaviour is attached to.</param> + /// <param name="info">The information about this frame</param> + public override void OnBehaviourPause(Playable playable, FrameData info) + { + // OnBehaviourPause can be called if the graph is stopped for a variety of reasons + // the effectivePlayState will test if the pause is due to the clip being out of bounds + if (gameObject != null && info.effectivePlayState == PlayState.Paused) + { + gameObject.SetActive(false); + } + } + + /// <summary> + /// This function is called during the ProcessFrame phase of the PlayableGraph. + /// </summary> + /// <param name="playable">The playable this behaviour is attached to.</param> + /// <param name="info">A FrameData structure that contains information about the current frame context.</param> + /// <param name="userData">unused</param> + public override void ProcessFrame(Playable playable, FrameData info, object userData) + { + if (gameObject != null)// && !gameObject.activeSelf) + gameObject.SetActive(true); + } + + /// <summary> + /// This function is called when the PlayableGraph that owns this PlayableBehaviour starts. + /// </summary> + /// <param name="playable">The playable this behaviour is attached to.</param> + public override void OnGraphStart(Playable playable) + { + if (gameObject != null) + { + if (m_InitialState == InitialState.Unset) + m_InitialState = gameObject.activeSelf ? InitialState.Active : InitialState.Inactive; + } + } + + /// <summary> + /// This function is called when the Playable that owns the PlayableBehaviour is destroyed. + /// </summary> + /// <param name="playable">The playable this behaviour is attached to.</param> + public override void OnPlayableDestroy(Playable playable) + { + if (gameObject == null || m_InitialState == InitialState.Unset) + return; + + switch (postPlayback) + { + case PostPlaybackState.Active: + gameObject.SetActive(true); + break; + + case PostPlaybackState.Inactive: + gameObject.SetActive(false); + break; + + case PostPlaybackState.Revert: + gameObject.SetActive(m_InitialState == InitialState.Active); + break; + } + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/ActivationControlPlayable.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/ActivationControlPlayable.cs.meta new file mode 100644 index 0000000..a7763a6 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/ActivationControlPlayable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d20e4e177b86a2843805dd3894f41b42 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/BasicScriptPlayable.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/BasicScriptPlayable.cs new file mode 100644 index 0000000..0157958 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/BasicScriptPlayable.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// This class is deprecated. It is recommended to use Playable Asset and Playable Behaviour derived classes instead. + /// </summary> + [Serializable] + [Obsolete("For best performance use PlayableAsset and PlayableBehaviour.")] + public class BasicPlayableBehaviour : ScriptableObject, IPlayableAsset, IPlayableBehaviour + { + public BasicPlayableBehaviour() {} + + /// <summary> + /// The playback duration in seconds of the instantiated Playable. + /// </summary> + public virtual double duration { get { return PlayableBinding.DefaultDuration; } } + + /// <summary> + ///A description of the outputs of the instantiated Playable. + /// </summary> + public virtual IEnumerable<PlayableBinding> outputs { get { return PlayableBinding.None; } } + + /// <summary> + /// <para>This function is called when the PlayableGraph that owns this PlayableBehaviour starts.</para> + /// </summary> + /// <param name="playable">The Playable that owns the current PlayableBehaviour.</param> + public virtual void OnGraphStart(Playable playable) {} + + /// <summary> + /// <para>This function is called when the PlayableGraph that owns this PlayableBehaviour stops.</para> + /// </summary> + /// <param name="playable">The Playable that owns the current PlayableBehaviour.</param> + public virtual void OnGraphStop(Playable playable) {} + + /// <summary> + /// <para>This function is called when the Playable that owns the PlayableBehaviour is created.</para> + /// </summary> + /// <param name="playable">The Playable that owns the current PlayableBehaviour.</param> + public virtual void OnPlayableCreate(Playable playable) {} + + /// <summary> + /// <para>This function is called when the Playable that owns the PlayableBehaviour is destroyed.</para> + /// </summary> + /// <param name="playable">The Playable that owns the current PlayableBehaviour.</param> + public virtual void OnPlayableDestroy(Playable playable) {} + + /// <summary> + /// <para>This function is called when the Playable play state is changed to Playables.PlayState.Playing.</para> + /// </summary> + /// <param name="playable">The Playable that owns the current PlayableBehaviour.</param> + /// <param name="info">A FrameData structure that contains information about the current frame context.</param> + public virtual void OnBehaviourPlay(Playable playable, FrameData info) {} + + /// <summary> + /// <para>This function is called when the Playable play state is changed to Playables.PlayState.Paused.</para> + /// </summary> + /// <param name="playable">The Playable that owns the current PlayableBehaviour.</param> + /// <param name="info">A FrameData structure that contains information about the current frame context.</param> + public virtual void OnBehaviourPause(Playable playable, FrameData info) {} + + /// <summary> + /// <para>This function is called during the PrepareFrame phase of the PlayableGraph.</para> + /// </summary> + /// <param name="playable">The Playable that owns the current PlayableBehaviour.</param> + /// <param name="info">A FrameData structure that contains information about the current frame context.</param> + public virtual void PrepareFrame(Playable playable, FrameData info) {} + + /// <summary> + /// <para>This function is called during the ProcessFrame phase of the PlayableGraph.</para> + /// </summary> + /// <param name="playable">The Playable that owns the current PlayableBehaviour.</param> + /// <param name="info">A FrameData structure that contains information about the current frame context.</param> + /// <param name="playerData">The user data of the ScriptPlayableOutput that initiated the process pass.</param> + public virtual void ProcessFrame(Playable playable, FrameData info, object playerData) {} + + /// <summary> + /// Implement this method to have your asset inject playables into the given graph. + /// </summary> + /// <param name="graph">The graph to inject playables into.</param> + /// <param name="owner">The game object which initiated the build.</param> + /// <returns>The playable injected into the graph, or the root playable if multiple playables are injected.</returns> + public virtual Playable CreatePlayable(PlayableGraph graph, GameObject owner) + { + return ScriptPlayable<BasicPlayableBehaviour>.Create(graph, this); + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/BasicScriptPlayable.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/BasicScriptPlayable.cs.meta new file mode 100644 index 0000000..414366e --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/BasicScriptPlayable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fe03a7b0ba57a4d488b6c327ae16c335 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/DirectorControlPlayable.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/DirectorControlPlayable.cs new file mode 100644 index 0000000..e619617 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/DirectorControlPlayable.cs @@ -0,0 +1,206 @@ +using System; +using UnityEngine; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// Playable Behaviour used to control a PlayableDirector. + /// </summary> + /// <remarks> + /// This playable is used to control other PlayableDirector components from a Timeline sequence. + /// </remarks> + public class DirectorControlPlayable : PlayableBehaviour + { + /// <summary> + /// The PlayableDirector being controlled by this PlayableBehaviour + /// </summary> + public PlayableDirector director; + + private bool m_SyncTime = false; + + private double m_AssetDuration = double.MaxValue; + + /// <summary> + /// Creates a Playable with a DirectorControlPlayable attached + /// </summary> + /// <param name="graph">The graph to inject the playable into</param> + /// <param name="director">The director to control</param> + /// <returns>Returns a Playable with a DirectorControlPlayable attached</returns> + public static ScriptPlayable<DirectorControlPlayable> Create(PlayableGraph graph, PlayableDirector director) + { + if (director == null) + return ScriptPlayable<DirectorControlPlayable>.Null; + + var handle = ScriptPlayable<DirectorControlPlayable>.Create(graph); + handle.GetBehaviour().director = director; + +#if UNITY_EDITOR + if (!Application.isPlaying && UnityEditor.PrefabUtility.IsPartOfPrefabInstance(director)) + UnityEditor.PrefabUtility.prefabInstanceUpdated += handle.GetBehaviour().OnPrefabUpdated; +#endif + + return handle; + } + + public override void OnPlayableDestroy(Playable playable) + { +#if UNITY_EDITOR + if (!Application.isPlaying) + UnityEditor.PrefabUtility.prefabInstanceUpdated -= OnPrefabUpdated; +#endif + if (director != null && director.playableAsset != null) + director.Stop(); + } + + /// <summary> + /// This function is called during the PrepareFrame phase of the PlayableGraph. + /// </summary> + /// <param name="playable">The Playable that owns the current PlayableBehaviour.</param> + /// <param name="info">A FrameData structure that contains information about the current frame context.</param> + public override void PrepareFrame(Playable playable, FrameData info) + { + if (director == null || !director.isActiveAndEnabled || director.playableAsset == null) + return; + + // resync the time on an evaluate or a time jump (caused by loops, or some setTime calls) + m_SyncTime |= (info.evaluationType == FrameData.EvaluationType.Evaluate) || + DetectDiscontinuity(playable, info); + + SyncSpeed(info.effectiveSpeed); + SyncPlayState(playable.GetGraph(), playable.GetTime()); + } + + /// <summary> + /// This function is called when the Playable play state is changed to Playables.PlayState.Playing. + /// </summary> + /// <param name="playable">The Playable that owns the current PlayableBehaviour.</param> + /// <param name="info">A FrameData structure that contains information about the current frame context.</param> + public override void OnBehaviourPlay(Playable playable, FrameData info) + { + m_SyncTime = true; + + if (director != null && director.playableAsset != null) + m_AssetDuration = director.playableAsset.duration; + } + + /// <summary> + /// This function is called when the Playable play state is changed to PlayState.Paused. + /// </summary> + /// <param name="playable">The playable this behaviour is attached to.</param> + /// <param name="info">A FrameData structure that contains information about the current frame context.</param> + public override void OnBehaviourPause(Playable playable, FrameData info) + { + if (director != null && director.playableAsset != null) + { + if (info.effectivePlayState == PlayState.Playing) // graph was paused + director.Pause(); + else + director.Stop(); + } + } + + /// <summary> + /// This function is called during the ProcessFrame phase of the PlayableGraph. + /// </summary> + /// <param name="playable">The playable this behaviour is attached to.</param> + /// <param name="info">A FrameData structure that contains information about the current frame context.</param> + /// <param name="playerData">unused</param> + public override void ProcessFrame(Playable playable, FrameData info, object playerData) + { + if (director == null || !director.isActiveAndEnabled || director.playableAsset == null) + return; + + if (m_SyncTime || DetectOutOfSync(playable)) + { + UpdateTime(playable); + director.Evaluate(); + } + + m_SyncTime = false; + } + +#if UNITY_EDITOR + void OnPrefabUpdated(GameObject go) + { + // When the prefab asset is updated, we rebuild the graph to reflect the changes in editor + if (UnityEditor.PrefabUtility.GetRootGameObject(director) == go) + director.RebuildGraph(); + } + +#endif + + void SyncSpeed(double speed) + { + if (director.playableGraph.IsValid()) + { + int roots = director.playableGraph.GetRootPlayableCount(); + for (int i = 0; i < roots; i++) + { + var rootPlayable = director.playableGraph.GetRootPlayable(i); + if (rootPlayable.IsValid()) + { + rootPlayable.SetSpeed(speed); + } + } + } + } + + void SyncPlayState(PlayableGraph graph, double playableTime) + { + bool expectedFinished = (playableTime >= m_AssetDuration) && director.extrapolationMode == DirectorWrapMode.None; + if (graph.IsPlaying() && !expectedFinished) + director.Play(); + else + director.Pause(); + } + + bool DetectDiscontinuity(Playable playable, FrameData info) + { + return Math.Abs(playable.GetTime() - playable.GetPreviousTime() - info.m_DeltaTime * info.m_EffectiveSpeed) > DiscreteTime.tickValue; + } + + bool DetectOutOfSync(Playable playable) + { + double expectedTime = playable.GetTime(); + if (playable.GetTime() >= m_AssetDuration) + { + if (director.extrapolationMode == DirectorWrapMode.None) + return false; + else if (director.extrapolationMode == DirectorWrapMode.Hold) + expectedTime = m_AssetDuration; + else if (m_AssetDuration > float.Epsilon) // loop + expectedTime = expectedTime % m_AssetDuration; + } + + if (!Mathf.Approximately((float)expectedTime, (float)director.time)) + { +#if UNITY_EDITOR + double lastDelta = playable.GetTime() - playable.GetPreviousTime(); + if (UnityEditor.Unsupported.IsDeveloperBuild()) + Debug.LogWarningFormat("Internal Warning - Control track desync detected on {2} ({0:F10} vs {1:F10} with delta {3:F10}). Time will be resynchronized. Known to happen with nested control tracks", playable.GetTime(), director.time, director.name, lastDelta); +#endif + return true; + } + return false; + } + + // We need to handle loop modes explicitly since we are setting the time directly + void UpdateTime(Playable playable) + { + double duration = Math.Max(0.1, director.playableAsset.duration); + switch (director.extrapolationMode) + { + case DirectorWrapMode.Hold: + director.time = Math.Min(duration, Math.Max(0, playable.GetTime())); + break; + case DirectorWrapMode.Loop: + director.time = Math.Max(0, playable.GetTime() % duration); + break; + case DirectorWrapMode.None: + director.time = playable.GetTime(); + break; + } + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/DirectorControlPlayable.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/DirectorControlPlayable.cs.meta new file mode 100644 index 0000000..5f71a6f --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/DirectorControlPlayable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: be156cc527d606b4aaac403e9843186e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/ITimeControl.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/ITimeControl.cs new file mode 100644 index 0000000..5d986ae --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/ITimeControl.cs @@ -0,0 +1,27 @@ +namespace UnityEngine.Timeline +{ + /// <summary> + /// Interface that can be implemented by MonoBehaviours indicating that they receive time-related control calls from a PlayableGraph. + /// </summary> + /// <remarks> + /// Implementing this interface on MonoBehaviours attached to GameObjects under control by control-tracks will cause them to be notified when associated Timeline clips are active. + /// </remarks> + public interface ITimeControl + { + /// <summary> + /// Called each frame the Timeline clip is active. + /// </summary> + /// <param name="time">The local time of the associated Timeline clip.</param> + void SetTime(double time); + + /// <summary> + /// Called when the associated Timeline clip becomes active. + /// </summary> + void OnControlTimeStart(); + + /// <summary> + /// Called when the associated Timeline clip becomes deactivated. + /// </summary> + void OnControlTimeStop(); + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/ITimeControl.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/ITimeControl.cs.meta new file mode 100644 index 0000000..8d4a953 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/ITimeControl.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5415c904c4fbc3e498253bc2866b37cd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/NotificationFlags.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/NotificationFlags.cs new file mode 100644 index 0000000..a83fc8b --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/NotificationFlags.cs @@ -0,0 +1,31 @@ +using System; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// Use these flags to specify the notification behaviour. + /// </summary> + /// <see cref="UnityEngine.Playables.INotification"/> + [Flags] + [Serializable] + public enum NotificationFlags : short + { + /// <summary> + /// Use this flag to send the notification in Edit Mode. + /// </summary> + /// <remarks> + /// Sent on discontinuous jumps in time. + /// </remarks> + TriggerInEditMode = 1 << 0, + + /// <summary> + /// Use this flag to send the notification if playback starts after the notification time. + /// </summary> + Retroactive = 1 << 1, + + /// <summary> + /// Use this flag to send the notification only once when looping. + /// </summary> + TriggerOnce = 1 << 2, + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/NotificationFlags.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/NotificationFlags.cs.meta new file mode 100644 index 0000000..4eae696 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/NotificationFlags.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 983c76d87fb6f4f4597a526a4b2b5fd7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/ParticleControlPlayable.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/ParticleControlPlayable.cs new file mode 100644 index 0000000..a513d7c --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/ParticleControlPlayable.cs @@ -0,0 +1,177 @@ +using System; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// Playable that synchronizes a particle system simulation. + /// </summary> + public class ParticleControlPlayable : PlayableBehaviour + { + const float kUnsetTime = -1; + float m_LastTime = kUnsetTime; + uint m_RandomSeed = 1; + + // particleSystem.time can not be relied on for an accurate time. It does not advance until a delta threshold is reached(fixedUpdate) and until the start delay has elapsed. + float m_SystemTime; + + /// <summary> + /// Creates a Playable with a ParticleControlPlayable behaviour attached + /// </summary> + /// <param name="graph">The PlayableGraph to inject the Playable into.</param> + /// <param name="component">The particle systtem to control</param> + /// <param name="randomSeed">A random seed to use for particle simulation</param> + /// <returns>Returns the created Playable.</returns> + public static ScriptPlayable<ParticleControlPlayable> Create(PlayableGraph graph, ParticleSystem component, uint randomSeed) + { + if (component == null) + return ScriptPlayable<ParticleControlPlayable>.Null; + + var handle = ScriptPlayable<ParticleControlPlayable>.Create(graph); + handle.GetBehaviour().Initialize(component, randomSeed); + return handle; + } + + /// <summary> + /// The particle system to control + /// </summary> + public ParticleSystem particleSystem { get; private set; } + + /// <summary> + /// Initializes the behaviour with a particle system and random seed. + /// </summary> + /// <param name="ps"></param> + /// <param name="randomSeed"></param> + public void Initialize(ParticleSystem ps, uint randomSeed) + { + m_RandomSeed = Math.Max(1, randomSeed); + particleSystem = ps; + m_SystemTime = 0; + SetRandomSeed(); + + #if UNITY_EDITOR + if (!Application.isPlaying && UnityEditor.PrefabUtility.IsPartOfPrefabInstance(ps)) + UnityEditor.PrefabUtility.prefabInstanceUpdated += OnPrefabUpdated; + #endif + } + + #if UNITY_EDITOR + /// <summary> + /// This function is called when the Playable that owns the PlayableBehaviour is destroyed. + /// </summary> + /// <param name="playable">The playable this behaviour is attached to.</param> + public override void OnPlayableDestroy(Playable playable) + { + if (!Application.isPlaying) + UnityEditor.PrefabUtility.prefabInstanceUpdated -= OnPrefabUpdated; + } + + void OnPrefabUpdated(GameObject go) + { + // When the instance is updated from, this will cause the next evaluate to resimulate. + if (UnityEditor.PrefabUtility.GetRootGameObject(particleSystem) == go) + m_LastTime = kUnsetTime; + } + + #endif + + void SetRandomSeed() + { + particleSystem.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear); + var systems = particleSystem.gameObject.GetComponentsInChildren<ParticleSystem>(); + uint seed = m_RandomSeed; + foreach (var ps in systems) + { + // don't overwrite user set random seeds + if (ps.useAutoRandomSeed) + { + ps.useAutoRandomSeed = false; + ps.randomSeed = seed; + seed++; + } + } + } + + /// <summary> + /// This function is called during the PrepareFrame phase of the PlayableGraph. + /// </summary> + /// <param name="playable">The Playable that owns the current PlayableBehaviour.</param> + /// <param name="data">A FrameData structure that contains information about the current frame context.</param> + public override void PrepareFrame(Playable playable, FrameData data) + { + if (particleSystem == null || !particleSystem.gameObject.activeInHierarchy) + return; + + float localTime = (float)playable.GetTime(); + bool shouldUpdate = Mathf.Approximately(m_LastTime, kUnsetTime) || + !Mathf.Approximately(m_LastTime, localTime); + if (shouldUpdate) + { + float epsilon = Time.fixedDeltaTime * 0.5f; + float simTime = localTime; + float expectedDelta = simTime - m_LastTime; + + // The first iteration includes the start delay. Evaluate(particleSystem.randomSeed) is how the particle system generates the random value internally. + float startDelay = particleSystem.main.startDelay.Evaluate(particleSystem.randomSeed); + float particleSystemDurationLoop0 = particleSystem.main.duration + startDelay; + + // The particle system time does not include the start delay so we need to remove this for our own system time. + float expectedSystemTime = simTime > particleSystemDurationLoop0 ? m_SystemTime : m_SystemTime - startDelay; + + // if it's not looping, then the system time won't advance past the end of the duration + if (!particleSystem.main.loop) + expectedSystemTime = Math.Min(expectedSystemTime, particleSystem.main.duration); + + + // conditions for restart + bool restart = (simTime < m_LastTime) || // time went backwards + (simTime < epsilon) || // time is set to 0 + Mathf.Approximately(m_LastTime, kUnsetTime) || // object disabled + (expectedDelta > particleSystem.main.duration) || // large jump (bug workaround) + !(Mathf.Abs(expectedSystemTime - particleSystem.time) < Time.maximumParticleDeltaTime); // particle system isn't where we left it + if (restart) + { + // work around for a bug where simulate(simTime, true, true) doesn't work on loops + particleSystem.Simulate(0, true, true); + particleSystem.Simulate(simTime, true, false); + m_SystemTime = simTime; + } + else + { + // ps.time will wrap, so we need to account for that in computing delta time + float particleSystemDuration = simTime > particleSystemDurationLoop0 ? particleSystem.main.duration : particleSystemDurationLoop0; + float fracTime = simTime % particleSystemDuration; + float deltaTime = fracTime - m_SystemTime; + + if (deltaTime < -epsilon) // detect wrapping of ps.time + deltaTime = fracTime + particleSystemDurationLoop0 - m_SystemTime; + + particleSystem.Simulate(deltaTime, true, false); + m_SystemTime += deltaTime; + } + + m_LastTime = localTime; + } + } + + /// <summary> + /// This function is called when the Playable play state is changed to Playables.PlayState.Playing. + /// </summary> + /// <param name="playable">The Playable that owns the current PlayableBehaviour.</param> + /// <param name="info">A FrameData structure that contains information about the current frame context.</param> + public override void OnBehaviourPlay(Playable playable, FrameData info) + { + m_LastTime = kUnsetTime; + } + + /// <summary> + /// This function is called when the Playable play state is changed to PlayState.Paused. + /// </summary> + /// <param name="playable">The playable this behaviour is attached to.</param> + /// <param name="info">A FrameData structure that contains information about the current frame context.</param> + public override void OnBehaviourPause(Playable playable, FrameData info) + { + m_LastTime = kUnsetTime; + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/ParticleControlPlayable.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/ParticleControlPlayable.cs.meta new file mode 100644 index 0000000..33db5b9 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/ParticleControlPlayable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f603edd7163537f44927ad2808147a25 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/PrefabControlPlayable.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/PrefabControlPlayable.cs new file mode 100644 index 0000000..f84c9ff --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/PrefabControlPlayable.cs @@ -0,0 +1,158 @@ +using System; +using UnityEngine.Playables; +using UnityEngine.SceneManagement; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// Playable that controls and instantiates a Prefab. + /// </summary> + public class PrefabControlPlayable : PlayableBehaviour + { + GameObject m_Instance; + +#if UNITY_EDITOR + private bool m_IsActiveCached; +#endif + + /// <summary> + /// Creates a Playable with a PrefabControlPlayable behaviour attached + /// </summary> + /// <param name="graph">The PlayableGraph to inject the Playable into.</param> + /// <param name="prefabGameObject">The prefab to instantiate from</param> + /// <param name="parentTransform">Transform to parent instance to. Can be null.</param> + /// <returns>Returns a Playabe with PrefabControlPlayable behaviour attached.</returns> + public static ScriptPlayable<PrefabControlPlayable> Create(PlayableGraph graph, GameObject prefabGameObject, Transform parentTransform) + { + if (prefabGameObject == null) + return ScriptPlayable<PrefabControlPlayable>.Null; + + var handle = ScriptPlayable<PrefabControlPlayable>.Create(graph); + handle.GetBehaviour().Initialize(prefabGameObject, parentTransform); + return handle; + } + + /// <summary> + /// The instance of the prefab created by this behaviour + /// </summary> + public GameObject prefabInstance + { + get { return m_Instance; } + } + + /// <summary> + /// Initializes the behaviour with a prefab and parent transform + /// </summary> + /// <param name="prefabGameObject">The prefab to instantiate from</param> + /// <param name="parentTransform">Transform to parent instance to. Can be null.</param> + /// <returns>The created instance</returns> + public GameObject Initialize(GameObject prefabGameObject, Transform parentTransform) + { + if (prefabGameObject == null) + throw new ArgumentNullException("Prefab cannot be null"); + + if (m_Instance != null) + { + Debug.LogWarningFormat("Prefab Control Playable ({0}) has already been initialized with a Prefab ({1}).", prefabGameObject.name, m_Instance.name); + } + else + { + #if UNITY_EDITOR + if (!Application.isPlaying) + { + m_Instance = (GameObject)UnityEditor.PrefabUtility.InstantiatePrefab(prefabGameObject, parentTransform); + UnityEditor.PrefabUtility.prefabInstanceUpdated += OnPrefabUpdated; + } + else + #endif + { + m_Instance = Object.Instantiate(prefabGameObject, parentTransform, false); + } + m_Instance.name = prefabGameObject.name + " [Timeline]"; + m_Instance.SetActive(false); + SetHideFlagsRecursive(m_Instance); + } + return m_Instance; + } + + /// <summary> + /// This function is called when the Playable that owns the PlayableBehaviour is destroyed. + /// </summary> + /// <param name="playable">The playable this behaviour is attached to.</param> + public override void OnPlayableDestroy(Playable playable) + { + if (m_Instance) + { + if (Application.isPlaying) + Object.Destroy(m_Instance); + else + Object.DestroyImmediate(m_Instance); + } + +#if UNITY_EDITOR + UnityEditor.PrefabUtility.prefabInstanceUpdated -= OnPrefabUpdated; +#endif + } + + /// <summary> + /// This function is called when the Playable play state is changed to Playables.PlayState.Playing. + /// </summary> + /// <param name="playable">The Playable that owns the current PlayableBehaviour.</param> + /// <param name="info">A FrameData structure that contains information about the current frame context.</param> + public override void OnBehaviourPlay(Playable playable, FrameData info) + { + if (m_Instance == null) + return; + + m_Instance.SetActive(true); + +#if UNITY_EDITOR + m_IsActiveCached = true; +#endif + } + + /// <summary> + /// This function is called when the Playable play state is changed to PlayState.Paused. + /// </summary> + /// <param name="playable">The playable this behaviour is attached to.</param> + /// <param name="info">A FrameData structure that contains information about the current frame context.</param> + public override void OnBehaviourPause(Playable playable, FrameData info) + { + // OnBehaviourPause can be called if the graph is stopped for a variety of reasons + // the effectivePlayState will test if the pause is due to the clip being out of bounds + if (m_Instance != null && info.effectivePlayState == PlayState.Paused) + { + m_Instance.SetActive(false); +#if UNITY_EDITOR + m_IsActiveCached = false; +#endif + } + } + +#if UNITY_EDITOR + void OnPrefabUpdated(GameObject go) + { + if (go == m_Instance) + { + SetHideFlagsRecursive(go); + go.SetActive(m_IsActiveCached); + } + } + +#endif + + static void SetHideFlagsRecursive(GameObject gameObject) + { + if (gameObject == null) + return; + + gameObject.hideFlags = HideFlags.DontSaveInBuild | HideFlags.DontSaveInEditor; + if (!Application.isPlaying) + gameObject.hideFlags |= HideFlags.HideInHierarchy; + foreach (Transform child in gameObject.transform) + { + SetHideFlagsRecursive(child.gameObject); + } + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/PrefabControlPlayable.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/PrefabControlPlayable.cs.meta new file mode 100644 index 0000000..c148dc2 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/PrefabControlPlayable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 439c018cf4619e94d9a92110ce0aa188 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/TimeControlPlayable.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/TimeControlPlayable.cs new file mode 100644 index 0000000..68ec80d --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/TimeControlPlayable.cs @@ -0,0 +1,85 @@ +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// A PlayableBehaviour that manages a component that implements the ITimeControl interface + /// </summary> + public class TimeControlPlayable : PlayableBehaviour + { + ITimeControl m_timeControl; + + bool m_started; + + /// <summary> + /// Creates a Playable with a TimeControlPlayable behaviour attached + /// </summary> + /// <param name="graph">The PlayableGraph to inject the Playable into.</param> + /// <param name="timeControl"></param> + /// <returns></returns> + public static ScriptPlayable<TimeControlPlayable> Create(PlayableGraph graph, ITimeControl timeControl) + { + if (timeControl == null) + return ScriptPlayable<TimeControlPlayable>.Null; + + var handle = ScriptPlayable<TimeControlPlayable>.Create(graph); + handle.GetBehaviour().Initialize(timeControl); + return handle; + } + + /// <summary> + /// Initializes the behaviour + /// </summary> + /// <param name="timeControl">Component that implements the ITimeControl interface</param> + public void Initialize(ITimeControl timeControl) + { + m_timeControl = timeControl; + } + + /// <summary> + /// This function is called during the PrepareFrame phase of the PlayableGraph. + /// </summary> + /// <param name="playable">The Playable that owns the current PlayableBehaviour.</param> + /// <param name="info">A FrameData structure that contains information about the current frame context.</param> + public override void PrepareFrame(Playable playable, FrameData info) + { + Debug.Assert(m_started, "PrepareFrame has been called without OnControlTimeStart being called first."); + if (m_timeControl != null) + m_timeControl.SetTime(playable.GetTime()); + } + + /// <summary> + /// This function is called when the Playable play state is changed to Playables.PlayState.Playing. + /// </summary> + /// <param name="playable">The Playable that owns the current PlayableBehaviour.</param> + /// <param name="info">A FrameData structure that contains information about the current frame context.</param> + public override void OnBehaviourPlay(Playable playable, FrameData info) + { + if (m_timeControl == null) + return; + + if (!m_started) + { + m_timeControl.OnControlTimeStart(); + m_started = true; + } + } + + /// <summary> + /// This function is called when the Playable play state is changed to PlayState.Paused. + /// </summary> + /// <param name="playable">The playable this behaviour is attached to.</param> + /// <param name="info">A FrameData structure that contains information about the current frame context.</param> + public override void OnBehaviourPause(Playable playable, FrameData info) + { + if (m_timeControl == null) + return; + + if (m_started) + { + m_timeControl.OnControlTimeStop(); + m_started = false; + } + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/TimeControlPlayable.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/TimeControlPlayable.cs.meta new file mode 100644 index 0000000..5ce09ad --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/TimeControlPlayable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1db879070d9a45f4c86cdf5e59616df5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/TimeNotificationBehaviour.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/TimeNotificationBehaviour.cs new file mode 100644 index 0000000..66a31d1 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/TimeNotificationBehaviour.cs @@ -0,0 +1,254 @@ +using System; +using System.Collections.Generic; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// Use this PlayableBehaviour to send notifications at a given time. + /// </summary> + /// <seealso cref="UnityEngine.Timeline.NotificationFlags"/> + public class TimeNotificationBehaviour : PlayableBehaviour + { + struct NotificationEntry + { + public double time; + public INotification payload; + public bool notificationFired; + public NotificationFlags flags; + + public bool triggerInEditor + { + get { return (flags & NotificationFlags.TriggerInEditMode) != 0; } + } + public bool prewarm + { + get { return (flags & NotificationFlags.Retroactive) != 0; } + } + public bool triggerOnce + { + get { return (flags & NotificationFlags.TriggerOnce) != 0; } + } + } + + readonly List<NotificationEntry> m_Notifications = new List<NotificationEntry>(); + double m_PreviousTime; + bool m_NeedSortNotifications; + + Playable m_TimeSource; + + /// <summary> + /// Sets an optional Playable that provides duration and Wrap mode information. + /// </summary> + /// <remarks> + /// timeSource is optional. By default, the duration and Wrap mode will come from the current Playable. + /// </remarks> + public Playable timeSource + { + set { m_TimeSource = value; } + } + + /// <summary> + /// Creates and initializes a ScriptPlayable with a TimeNotificationBehaviour. + /// </summary> + /// <param name="graph">The playable graph.</param> + /// <param name="duration">The duration of the playable.</param> + /// <param name="loopMode">The loop mode of the playable.</param> + /// <returns>A new TimeNotificationBehaviour linked to the PlayableGraph.</returns> + public static ScriptPlayable<TimeNotificationBehaviour> Create(PlayableGraph graph, double duration, DirectorWrapMode loopMode) + { + var notificationsPlayable = ScriptPlayable<TimeNotificationBehaviour>.Create(graph); + notificationsPlayable.SetDuration(duration); + notificationsPlayable.SetTimeWrapMode(loopMode); + notificationsPlayable.SetPropagateSetTime(true); + return notificationsPlayable; + } + + /// <summary> + /// Adds a notification to be sent with flags, at a specific time. + /// </summary> + /// <param name="time">The time to send the notification.</param> + /// <param name="payload">The notification.</param> + /// <param name="flags">The notification flags that determine the notification behaviour. This parameter is set to Retroactive by default.</param> + /// <seealso cref="UnityEngine.Timeline.NotificationFlags"/> + public void AddNotification(double time, INotification payload, NotificationFlags flags = NotificationFlags.Retroactive) + { + m_Notifications.Add(new NotificationEntry + { + time = time, + payload = payload, + flags = flags + }); + m_NeedSortNotifications = true; + } + + /// <summary> + /// This method is called when the PlayableGraph that owns this PlayableBehaviour starts. + /// </summary> + /// <param name="playable">The reference to the playable associated with this PlayableBehaviour.</param> + public override void OnGraphStart(Playable playable) + { + SortNotifications(); + for (var i = 0; i < m_Notifications.Count; i++) + { + var notification = m_Notifications[i]; + notification.notificationFired = false; + m_Notifications[i] = notification; + } + + m_PreviousTime = playable.GetTime(); + } + + /// <summary> + /// This method is called when the Playable play state is changed to PlayState.Paused + /// </summary> + /// <param name="playable">The reference to the playable associated with this PlayableBehaviour.</param> + /// <param name="info">Playable context information such as weight, evaluationType, and so on.</param> + public override void OnBehaviourPause(Playable playable, FrameData info) + { + if (playable.IsDone()) + { + SortNotifications(); + for (var i = 0; i < m_Notifications.Count; i++) + { + var e = m_Notifications[i]; + if (!e.notificationFired) + { + var duration = playable.GetDuration(); + var canTrigger = m_PreviousTime <= e.time && e.time <= duration; + if (canTrigger) + { + Trigger_internal(playable, info.output, ref e); + m_Notifications[i] = e; + } + } + } + } + } + + /// <summary> + /// This method is called during the PrepareFrame phase of the PlayableGraph. + /// </summary> + /// <remarks> + /// Called once before processing starts. + /// </remarks> + /// <param name="playable">The reference to the playable associated with this PlayableBehaviour.</param> + /// <param name="info">Playable context information such as weight, evaluationType, and so on.</param> + public override void PrepareFrame(Playable playable, FrameData info) + { + // Never trigger on scrub + if (info.evaluationType == FrameData.EvaluationType.Evaluate) + { + return; + } + + SyncDurationWithExternalSource(playable); + SortNotifications(); + var currentTime = playable.GetTime(); + + // Fire notifications from previousTime till the end + if (info.timeLooped) + { + var duration = playable.GetDuration(); + TriggerNotificationsInRange(m_PreviousTime, duration, info, playable, true); + var dx = playable.GetDuration() - m_PreviousTime; + var nFullTimelines = (int)((info.deltaTime * info.effectiveSpeed - dx) / playable.GetDuration()); + for (var i = 0; i < nFullTimelines; i++) + { + TriggerNotificationsInRange(0, duration, info, playable, false); + } + TriggerNotificationsInRange(0, currentTime, info, playable, false); + } + else + { + var pt = playable.GetTime(); + TriggerNotificationsInRange(m_PreviousTime, pt, info, + playable, true); + } + + for (var i = 0; i < m_Notifications.Count; ++i) + { + var e = m_Notifications[i]; + if (e.notificationFired && CanRestoreNotification(e, info, currentTime, m_PreviousTime)) + { + Restore_internal(ref e); + m_Notifications[i] = e; + } + } + + m_PreviousTime = playable.GetTime(); + } + + void SortNotifications() + { + if (m_NeedSortNotifications) + { + m_Notifications.Sort((x, y) => x.time.CompareTo(y.time)); + m_NeedSortNotifications = false; + } + } + + static bool CanRestoreNotification(NotificationEntry e, FrameData info, double currentTime, double previousTime) + { + if (e.triggerOnce) + return false; + if (info.timeLooped) + return true; + + //case 1111595: restore the notification if the time is manually set before it + return previousTime > currentTime && currentTime <= e.time; + } + + void TriggerNotificationsInRange(double start, double end, FrameData info, Playable playable, bool checkState) + { + if (start <= end) + { + var playMode = Application.isPlaying; + for (var i = 0; i < m_Notifications.Count; i++) + { + var e = m_Notifications[i]; + if (e.notificationFired && (checkState || e.triggerOnce)) + continue; + + var notificationTime = e.time; + if (e.prewarm && notificationTime < end && (e.triggerInEditor || playMode)) + { + Trigger_internal(playable, info.output, ref e); + m_Notifications[i] = e; + } + else + { + if (notificationTime < start || notificationTime > end) + continue; + + if (e.triggerInEditor || playMode) + { + Trigger_internal(playable, info.output, ref e); + m_Notifications[i] = e; + } + } + } + } + } + + void SyncDurationWithExternalSource(Playable playable) + { + if (m_TimeSource.IsValid()) + { + playable.SetDuration(m_TimeSource.GetDuration()); + playable.SetTimeWrapMode(m_TimeSource.GetTimeWrapMode()); + } + } + + static void Trigger_internal(Playable playable, PlayableOutput output, ref NotificationEntry e) + { + output.PushNotification(playable, e.payload); + e.notificationFired = true; + } + + static void Restore_internal(ref NotificationEntry e) + { + e.notificationFired = false; + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/TimeNotificationBehaviour.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/TimeNotificationBehaviour.cs.meta new file mode 100644 index 0000000..593b6c2 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/TimeNotificationBehaviour.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: afeb55855d7a63b45ba6f8bd97599202 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Properties.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Properties.meta new file mode 100644 index 0000000..d06db75 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Properties.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ff97302ee78d6ad478b433ec557ee303 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Properties/AssemblyInfo.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..1eaacad --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Properties/AssemblyInfo.cs @@ -0,0 +1,28 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("UnityEngine.Timeline")] +[assembly: AssemblyDescription("Unity Timeline")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Unity Technologies")] +[assembly: AssemblyProduct("UnityEngine.Timeline")] +[assembly: AssemblyCopyright("Copyright � 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: InternalsVisibleTo("Unity.Timeline.Editor")] +[assembly: ComVisible(false)] +#if UNITY_EDITOR // RuntimeEditor version +[assembly: Guid("844F8153-91DB-42D4-9455-CBF1A7BFC434")] +#else // Runtime version +[assembly: Guid("6A10B290-9283-487F-913B-00D94CD3FAF5")] +#endif +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: InternalsVisibleTo("Assembly-CSharp-testable")] +[assembly: InternalsVisibleTo("Assembly-CSharp-Editor-testable")] +[assembly: InternalsVisibleTo("Unity.Timeline.EditorTests")] +[assembly: InternalsVisibleTo("Unity.Timeline.Tests")] +[assembly: InternalsVisibleTo("Unity.Timeline.Tests.Common")] +[assembly: InternalsVisibleTo("Unity.Timeline.Tests.Performance")] +[assembly: InternalsVisibleTo("Unity.Timeline.Tests.Performance.Editor")] diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Properties/AssemblyInfo.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Properties/AssemblyInfo.cs.meta new file mode 100644 index 0000000..01b8128 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Properties/AssemblyInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0bb74b1c097396c49b1691e6a938f814 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Scripting.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Scripting.meta new file mode 100644 index 0000000..fe679ff --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Scripting.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bdb4f6935641b574b984da8dc27cab45 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Scripting/PlayableTrack.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Scripting/PlayableTrack.cs new file mode 100644 index 0000000..e785cbf --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Scripting/PlayableTrack.cs @@ -0,0 +1,23 @@ +using System; +using UnityEngine; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// A PlayableTrack is a track whose clips are custom playables. + /// </summary> + /// <remarks> + /// This is a track that can contain PlayableAssets that are found in the project and do not have their own specified track type. + /// </remarks> + [Serializable] + public class PlayableTrack : TrackAsset + { + /// <inheritdoc /> + protected override void OnCreateClip(TimelineClip clip) + { + if (clip.asset != null) + clip.displayName = clip.asset.GetType().Name; + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Scripting/PlayableTrack.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Scripting/PlayableTrack.cs.meta new file mode 100644 index 0000000..0129ea2 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Scripting/PlayableTrack.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 82cd92ffc29383742932b27ca414c80f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Timeline.deprecated.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Timeline.deprecated.cs new file mode 100644 index 0000000..ac2b4c2 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Timeline.deprecated.cs @@ -0,0 +1,34 @@ +using System; +using UnityEngine; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + public partial class TimelineAsset + { + [Obsolete("MediaType has been deprecated. It is no longer required, and will be removed in a future release.", false)] + public enum MediaType + { + Animation, + Audio, + Texture = 2, + [Obsolete("Use Texture MediaType instead. (UnityUpgradable) -> UnityEngine.Timeline.TimelineAsset/MediaType.Texture", false)] Video = 2, + Script, + Hybrid, + Group + } + } + + // Defines the type of a track + [AttributeUsage(AttributeTargets.Class)] + [Obsolete("TrackMediaType has been deprecated. It is no longer required, and will be removed in a future release.", false)] + public class TrackMediaType : Attribute + { + public readonly TimelineAsset.MediaType m_MediaType; + + public TrackMediaType(TimelineAsset.MediaType mt) + { + m_MediaType = mt; + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Timeline.deprecated.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Timeline.deprecated.cs.meta new file mode 100644 index 0000000..cd16af0 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Timeline.deprecated.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7748a1d3701ac824ea7f366ba0388f5d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelineAsset.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelineAsset.cs new file mode 100644 index 0000000..ca2572e --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelineAsset.cs @@ -0,0 +1,455 @@ +using System; +using System.Collections.Generic; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// A PlayableAsset that represents a timeline. + /// </summary> + [ExcludeFromPreset] + [Serializable] + public partial class TimelineAsset : PlayableAsset, ISerializationCallbackReceiver, ITimelineClipAsset, IPropertyPreview + { + /// <summary> + /// How the duration of the timeline is determined. + /// </summary> + public enum DurationMode + { + /// <summary> + /// The duration of the timeline is determined based on the clips present. + /// </summary> + BasedOnClips, + /// <summary> + /// The duration of the timeline is a fixed length. + /// </summary> + FixedLength + } + + /// <summary> + /// Properties of the timeline that are used by the editor + /// </summary> + [Serializable] + public class EditorSettings + { + internal static readonly float kMinFps = (float)TimeUtility.kFrameRateEpsilon; + internal static readonly float kMaxFps = 1000.0f; + internal static readonly float kDefaultFps = 60.0f; + [HideInInspector, SerializeField] float m_Framerate = kDefaultFps; + + /// <summary> + /// The frames per second used for snapping and time ruler display + /// </summary> + public float fps + { + get + { + return m_Framerate; + } + set + { + m_Framerate = GetValidFramerate(value); + } + } + } + + [HideInInspector, SerializeField] List<ScriptableObject> m_Tracks; + [HideInInspector, SerializeField] double m_FixedDuration; // only applied if duration mode is Fixed + [HideInInspector, NonSerialized] TrackAsset[] m_CacheOutputTracks; + [HideInInspector, NonSerialized] List<TrackAsset> m_CacheRootTracks; + [HideInInspector, NonSerialized] List<TrackAsset> m_CacheFlattenedTracks; + [HideInInspector, SerializeField] EditorSettings m_EditorSettings = new EditorSettings(); + [SerializeField] DurationMode m_DurationMode; + + [HideInInspector, SerializeField] MarkerTrack m_MarkerTrack; + + /// <summary> + /// Settings used by timeline for editing purposes + /// </summary> + public EditorSettings editorSettings + { + get { return m_EditorSettings; } + } + + /// <summary> + /// The length, in seconds, of the timeline + /// </summary> + public override double duration + { + get + { + // @todo cache this value when rebuilt + if (m_DurationMode == DurationMode.BasedOnClips) + return CalculateDuration(); + + return m_FixedDuration; + } + } + + /// <summary> + /// The length of the timeline when durationMode is set to fixed length. + /// </summary> + public double fixedDuration + { + get + { + DiscreteTime discreteDuration = (DiscreteTime)m_FixedDuration; + if (discreteDuration <= 0) + return 0.0; + + //avoid having no clip evaluated at the end by removing a tick from the total duration + return (double)discreteDuration.OneTickBefore(); + } + set { m_FixedDuration = Math.Max(0.0, value); } + } + + /// <summary> + /// The mode used to determine the duration of the Timeline + /// </summary> + public DurationMode durationMode + { + get { return m_DurationMode; } + set { m_DurationMode = value; } + } + + /// <summary> + /// A description of the PlayableOutputs that will be created by the timeline when instantiated. + /// </summary> + /// <remarks> + /// Each track will create an PlayableOutput + /// </remarks> + public override IEnumerable<PlayableBinding> outputs + { + get + { + foreach (var outputTracks in GetOutputTracks()) + foreach (var output in outputTracks.outputs) + yield return output; + } + } + + public ClipCaps clipCaps + { + get + { + var caps = ClipCaps.All; + foreach (var track in GetRootTracks()) + { + foreach (var clip in track.clips) + caps &= clip.clipCaps; + } + return caps; + } + } + + /// <summary> + /// Returns the the number of output tracks in the Timeline. + /// </summary> + /// <remarks> + /// An output track is a track the generates a PlayableOutput. In general, an output track is any track that is not a GroupTrack, a subtrack, or override track. + /// </remarks> + public int outputTrackCount + { + get + { + UpdateOutputTrackCache(); // updates the cache if necessary + return m_CacheOutputTracks.Length; + } + } + + /// <summary> + /// Returns the number of tracks at the root level of the timeline. + /// </summary> + /// <remarks> + /// A root track refers to all tracks that occur at the root of the timeline. These are the outmost level GroupTracks, and output tracks that do not belong to any group + /// </remarks> + public int rootTrackCount + { + get + { + UpdateRootTrackCache(); + return m_CacheRootTracks.Count; + } + } + + void OnValidate() + { + editorSettings.fps = GetValidFramerate(editorSettings.fps); + } + + static float GetValidFramerate(float framerate) + { + return Mathf.Clamp(framerate, EditorSettings.kMinFps, EditorSettings.kMaxFps); + } + + /// <summary> + /// Retrieves at root track at the specified index. + /// </summary> + /// <param name="index">Index of the root track to get. Must be between 0 and rootTrackCount</param> + /// <remarks> + /// A root track refers to all tracks that occur at the root of the timeline. These are the outmost level GroupTracks, and output tracks that do not belong to any group. + /// </remarks> + public TrackAsset GetRootTrack(int index) + { + UpdateRootTrackCache(); + return m_CacheRootTracks[index]; + } + + /// <summary> + /// Get an enumerable list of all root tracks. + /// </summary> + /// <returns>An IEnumerable of all root tracks.</returns> + /// <remarks>A root track refers to all tracks that occur at the root of the timeline. These are the outmost level GroupTracks, and output tracks that do not belong to any group.</remarks> + public IEnumerable<TrackAsset> GetRootTracks() + { + UpdateRootTrackCache(); + return m_CacheRootTracks; + } + + /// <summary> + /// Retrives the output track from the given index. + /// </summary> + /// <param name="index">Index of the output track to retrieve. Must be between 0 and outputTrackCount</param> + /// <returns>The output track from the given index</returns> + public TrackAsset GetOutputTrack(int index) + { + UpdateOutputTrackCache(); + return m_CacheOutputTracks[index]; + } + + /// <summary> + /// Gets a list of all output tracks in the Timeline. + /// </summary> + /// <returns>An IEnumerable of all output tracks</returns> + /// <remarks> + /// An output track is a track the generates a PlayableOutput. In general, an output track is any track that is not a GroupTrack or subtrack. + /// </remarks> + public IEnumerable<TrackAsset> GetOutputTracks() + { + UpdateOutputTrackCache(); + return m_CacheOutputTracks; + } + + void UpdateRootTrackCache() + { + if (m_CacheRootTracks == null) + { + if (m_Tracks == null) + m_CacheRootTracks = new List<TrackAsset>(); + else + { + m_CacheRootTracks = new List<TrackAsset>(m_Tracks.Count); + if (markerTrack != null) + { + m_CacheRootTracks.Add(markerTrack); + } + + foreach (var t in m_Tracks) + { + var trackAsset = t as TrackAsset; + if (trackAsset != null) + m_CacheRootTracks.Add(trackAsset); + } + } + } + } + + void UpdateOutputTrackCache() + { + if (m_CacheOutputTracks == null) + { + var outputTracks = new List<TrackAsset>(); + foreach (var flattenedTrack in flattenedTracks) + { + if (flattenedTrack != null && flattenedTrack.GetType() != typeof(GroupTrack) && !flattenedTrack.isSubTrack) + outputTracks.Add(flattenedTrack); + } + m_CacheOutputTracks = outputTracks.ToArray(); + } + } + + internal IEnumerable<TrackAsset> flattenedTracks + { + get + { + if (m_CacheFlattenedTracks == null) + { + m_CacheFlattenedTracks = new List<TrackAsset>(m_Tracks.Count * 2); + UpdateRootTrackCache(); + + m_CacheFlattenedTracks.AddRange(m_CacheRootTracks); + for (int i = 0; i < m_CacheRootTracks.Count; i++) + { + AddSubTracksRecursive(m_CacheRootTracks[i], ref m_CacheFlattenedTracks); + } + } + return m_CacheFlattenedTracks; + } + } + + /// <summary> + /// Gets the marker track for this TimelineAsset. + /// </summary> + /// <returns>Returns the marker track.</returns> + /// <remarks> + /// Use <see cref="TrackAsset.GetMarkers"/> to get a list of the markers on the returned track. + /// </remarks> + public MarkerTrack markerTrack + { + get { return m_MarkerTrack; } + } + + // access to the track list as scriptable object + internal List<ScriptableObject> trackObjects + { + get { return m_Tracks; } + } + + internal void AddTrackInternal(TrackAsset track) + { + m_Tracks.Add(track); + track.parent = this; + Invalidate(); + } + + internal void RemoveTrack(TrackAsset track) + { + m_Tracks.Remove(track); + Invalidate(); + var parentTrack = track.parent as TrackAsset; + if (parentTrack != null) + { + parentTrack.RemoveSubTrack(track); + } + } + + /// <summary> + /// Creates an instance of the timeline + /// </summary> + /// <param name="graph">PlayableGraph that will own the playable</param> + /// <param name="go">The gameobject that triggered the graph build</param> + /// <returns>The Root Playable of the Timeline</returns> + public override Playable CreatePlayable(PlayableGraph graph, GameObject go) + { + bool autoRebalanceTree = false; + #if UNITY_EDITOR + autoRebalanceTree = true; + #endif + + // only create outputs if we are not nested + bool createOutputs = graph.GetPlayableCount() == 0; + var timeline = TimelinePlayable.Create(graph, GetOutputTracks(), go, autoRebalanceTree, createOutputs); + timeline.SetPropagateSetTime(true); + return timeline.IsValid() ? timeline : Playable.Null; + } + + void ISerializationCallbackReceiver.OnBeforeSerialize() + { + m_Version = k_LatestVersion; + } + + // resets cache on an Undo + void ISerializationCallbackReceiver.OnAfterDeserialize() + { + Invalidate(); // resets cache on an Undo + if (m_Version < k_LatestVersion) + { + UpgradeToLatestVersion(); + } + } + + void __internalAwake() + { + if (m_Tracks == null) + m_Tracks = new List<ScriptableObject>(); + + // validate the array. DON'T remove Unity null objects, just actual null objects + for (int i = m_Tracks.Count - 1; i >= 0; i--) + { + TrackAsset asset = m_Tracks[i] as TrackAsset; + if (asset != null) + asset.parent = this; +#if UNITY_EDITOR + object o = m_Tracks[i]; + if (o == null) + { + Debug.LogWarning("Empty track found while loading timeline. It will be removed."); + m_Tracks.RemoveAt(i); + } +#endif + } + } + + /// <summary> + /// Called by the Timeline Editor to gather properties requiring preview. + /// </summary> + /// <param name="director">The PlayableDirector invoking the preview</param> + /// <param name="driver">PropertyCollector used to gather previewable properties</param> + public void GatherProperties(PlayableDirector director, IPropertyCollector driver) + { + var outputTracks = GetOutputTracks(); + foreach (var track in outputTracks) + { + track.GatherProperties(director, driver); + } + } + + /// <summary> + /// Creates a marker track for the TimelineAsset. + /// </summary> + /// In the editor, the marker track appears under the Timeline ruler. + /// <remarks> + /// This track is always bound to the GameObject that contains the PlayableDirector component for the current timeline. + /// The marker track is created the first time this method is called. If the marker track is already created, this method does nothing. + /// </remarks> + public void CreateMarkerTrack() + { + if (m_MarkerTrack == null) + { + m_MarkerTrack = CreateInstance<MarkerTrack>(); + TimelineCreateUtilities.SaveAssetIntoObject(m_MarkerTrack, this); + m_MarkerTrack.parent = this; + m_MarkerTrack.name = "Markers"; // This name will show up in the bindings list if it contains signals + Invalidate(); + } + } + + // Invalidates the asset, call this if changing the asset data + internal void Invalidate() + { + m_CacheRootTracks = null; + m_CacheOutputTracks = null; + m_CacheFlattenedTracks = null; + } + + double CalculateDuration() + { + var discreteDuration = new DiscreteTime(0); + foreach (var track in flattenedTracks) + { + if (track.muted) + continue; + + discreteDuration = DiscreteTime.Max(discreteDuration, (DiscreteTime)track.end); + } + + if (discreteDuration <= 0) + return 0.0; + + //avoid having no clip evaluated at the end by removing a tick from the total duration + return (double)discreteDuration.OneTickBefore(); + } + + static void AddSubTracksRecursive(TrackAsset track, ref List<TrackAsset> allTracks) + { + if (track == null) + return; + + allTracks.AddRange(track.GetChildTracks()); + foreach (TrackAsset subTrack in track.GetChildTracks()) + { + AddSubTracksRecursive(subTrack, ref allTracks); + } + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelineAsset.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelineAsset.cs.meta new file mode 100644 index 0000000..d4c4836 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelineAsset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bfda56da833e2384a9677cd3c976a436 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelineAsset_CreateRemove.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelineAsset_CreateRemove.cs new file mode 100644 index 0000000..8727eae --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelineAsset_CreateRemove.cs @@ -0,0 +1,255 @@ +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) + { + TimelineUndo.PushDestroyUndo(this, clip.parentTrack, clip.curves, "Delete Curves"); + } + + // 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 + { + TimelineUndo.PushDestroyUndo(this, clip.parentTrack, clip.asset, "Delete Clip Asset"); + } + } + + 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); + + TimelineUndo.PushDestroyUndo(this, this, track, "Delete Track"); + + 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) + TimelineUndo.PushDestroyUndo(this, track, animTrack.infiniteClip, "Delete Track"); + + if (track.curves != null) + TimelineUndo.PushDestroyUndo(this, track, track.curves, "Delete Track Parameters"); + } + + void DeleteRecordedAnimation(TimelineClip clip) + { + if (clip == null) + return; + + if (clip.curves != null) + TimelineUndo.PushDestroyUndo(this, clip.parentTrack, clip.curves, "Delete Clip Parameters"); + + if (!clip.recordable) + return; + + AnimationPlayableAsset asset = clip.asset as AnimationPlayableAsset; + if (asset == null || asset.clip == null) + return; + + TimelineUndo.PushDestroyUndo(this, asset, asset.clip, "Delete Recording"); + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelineAsset_CreateRemove.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelineAsset_CreateRemove.cs.meta new file mode 100644 index 0000000..76d1df6 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelineAsset_CreateRemove.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 93665e8b67658804d99c4487228cc050 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelineAttributes.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelineAttributes.cs new file mode 100644 index 0000000..69409fd --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelineAttributes.cs @@ -0,0 +1,222 @@ +using System; +using UnityEngine; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// Specifies the type of PlayableAsset that a TrackAsset derived class can create clips of. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] + public class TrackClipTypeAttribute : Attribute + { + /// <summary> + /// The type of the clip class associate with this track + /// </summary> + public readonly Type inspectedType; + + /// <summary> + /// Whether to allow automatic creation of these types. + /// </summary> + public readonly bool allowAutoCreate; // true will make it show up in menus + + /// <summary> + /// </summary> + /// <param name="clipClass">The type of the clip class to associate with this track. Must derive from PlayableAsset.</param> + public TrackClipTypeAttribute(Type clipClass) + { + inspectedType = clipClass; + allowAutoCreate = true; + } + + /// <summary> + /// </summary> + /// <param name="clipClass">The type of the clip class to associate with this track. Must derive from PlayableAsset.</param> + /// <param name="allowAutoCreate">Whether to allow automatic creation of these types. Default value is true.</param> + /// <remarks>Setting allowAutoCreate to false will cause Timeline to not show menu items for creating clips of this type.</remarks> + public TrackClipTypeAttribute(Type clipClass, bool allowAutoCreate) + { + inspectedType = clipClass; + allowAutoCreate = false; + } + } + + /// <summary> + /// Apply this to a PlayableBehaviour class or field to indicate that it is not animatable. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Class)] + public class NotKeyableAttribute : Attribute + { + } + + + /// <summary> + /// Options for track binding + /// </summary> + [Flags] + public enum TrackBindingFlags + { + /// <summary> + /// No options specified + /// </summary> + None = 0, + + /// <summary> + /// Allow automatic creating of component during gameObject drag and drop + /// </summary> + AllowCreateComponent = 1, + + /// <summary> + /// All options specified + /// </summary> + All = AllowCreateComponent + } + + /// <summary> + /// Specifies the type of object that should be bound to a TrackAsset. + /// </summary> + /// <example> + /// <code> + /// using UnityEngine; + /// using UnityEngine.Timeline; + /// [TrackBindingType(typeof(Light), TrackBindingFlags.AllowCreateComponent)] + /// public class LightTrack : TrackAsset + /// { + /// } + /// </code> + /// </example> + /// <remarks> + /// Use this attribute when creating Custom Tracks to specify the type of object the track requires a binding to. + /// </remarks> + [AttributeUsage(AttributeTargets.Class)] + public class TrackBindingTypeAttribute : Attribute + { + /// <summary> + /// The type of binding for the associate track + /// </summary> + public readonly Type type; + + /// <summary> + /// Options for the the track binding + /// </summary> + public readonly TrackBindingFlags flags; + + public TrackBindingTypeAttribute(Type type) + { + this.type = type; + this.flags = TrackBindingFlags.All; + } + + public TrackBindingTypeAttribute(Type type, TrackBindingFlags flags) + { + this.type = type; + this.flags = flags; + } + } + + // indicates that child tracks are permitted on a track + // internal because not fully supported on custom classes yet + [AttributeUsage(AttributeTargets.Class, Inherited = false)] + class SupportsChildTracksAttribute : Attribute + { + public readonly Type childType; + public readonly int levels; + + public SupportsChildTracksAttribute(Type childType = null, int levels = Int32.MaxValue) + { + this.childType = childType; + this.levels = levels; + } + } + + // indicates that the type should not be put on a PlayableTrack + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + class IgnoreOnPlayableTrackAttribute : System.Attribute {} + + // used to flag properties as using a time field (second/frames) display + class TimeFieldAttribute : PropertyAttribute + { + public enum UseEditMode + { + None, + ApplyEditMode + } + public UseEditMode useEditMode { get; } + + public TimeFieldAttribute(UseEditMode useEditMode = UseEditMode.ApplyEditMode) + { + this.useEditMode = useEditMode; + } + } + + /// <summary> + /// Use this attribute to hide a class from Timeline menus. + /// </summary> + [AttributeUsage(AttributeTargets.Class, Inherited = false)] + public class HideInMenuAttribute : Attribute {} + + ///<summary> + /// Use this attribute to customize the appearance of a Marker. + /// </summary> + /// Specify the style to use to draw a Marker. + /// <example> + /// [CustomStyle("MyStyle")] + /// public class MyMarker : UnityEngine.Timeline.Marker {} + /// </example> + /// How to create a custom style rule: + /// 1) Create a 'common.uss' USS file in an Editor folder in a StyleSheets/Extensions folder hierarchy. + /// Example of valid folder paths: + /// - Assets/Editor/StyleSheets/Extensions + /// - Assets/Editor/Markers/StyleSheets/Extensions + /// - Assets/Timeline/Editor/MyMarkers/StyleSheets/Extensions + /// Rules in 'dark.uss' are used if you use the Pro Skin and rules in 'light.uss' are used otherwise. + /// + /// 2)In the USS file, create a styling rule to customize the appearance of the marker. + /// <example> + /// MyStyle + /// { + /// /* Specify the appearance of the marker in the collapsed state here. */ + /// } + /// + /// MyStyle:checked + /// { + /// /* Specify the appearance of the marker in the expanded state here. */ + /// } + /// + /// MyStyle:focused:checked + /// { + /// /* Specify the appearance of the marker in the selected state here. */ + /// } + /// </example> + /// <seealso cref="UnityEngine.Timeline.Marker"/> + [AttributeUsage(AttributeTargets.Class)] + public class CustomStyleAttribute : Attribute + { + /// <summary> + /// The name of the USS style. + /// </summary> + public readonly string ussStyle; + + /// <param name="ussStyle">The name of the USS style.</param> + public CustomStyleAttribute(string ussStyle) + { + this.ussStyle = ussStyle; + } + } + + /// <summary> + /// Use this attribute to assign a clip, marker or track to a category in a submenu + /// </summary> + [AttributeUsage(AttributeTargets.Class)] + internal class MenuCategoryAttribute : Attribute + { + /// <summary> + /// The menu name of the category + /// </summary> + public readonly string category; + + public MenuCategoryAttribute(string category) + { + this.category = category ?? string.Empty; + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelineAttributes.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelineAttributes.cs.meta new file mode 100644 index 0000000..ae5547d --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelineAttributes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3e99141cd5dbef844a4338bb87930b89 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelineClip.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelineClip.cs new file mode 100644 index 0000000..f1aa05b --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelineClip.cs @@ -0,0 +1,821 @@ +using System; +using System.Collections.Generic; +using UnityEngine.Playables; +using UnityEngine.Serialization; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// Implement this interface to support advanced features of timeline clips. + /// </summary> + public interface ITimelineClipAsset + { + /// <summary> + /// Returns a description of the features supported by clips with PlayableAssets implementing this interface. + /// </summary> + ClipCaps clipCaps { get; } + } + + /// <summary> + /// Represents a clip on the timeline. + /// </summary> + [Serializable] + public partial class TimelineClip : ICurvesOwner, ISerializationCallbackReceiver + { + /// <summary> + /// The default capabilities for a clip + /// </summary> + public static readonly ClipCaps kDefaultClipCaps = ClipCaps.Blending; + + /// <summary> + /// The default length of a clip in seconds. + /// </summary> + public static readonly float kDefaultClipDurationInSeconds = 5; + + /// <summary> + /// The minimum timescale allowed on a clip + /// </summary> + public static readonly double kTimeScaleMin = 1.0 / 1000; + + /// <summary> + /// The maximum timescale allowed on a clip + /// </summary> + public static readonly double kTimeScaleMax = 1000; + + internal static readonly string kDefaultCurvesName = "Clip Parameters"; + + internal static readonly double kMinDuration = 1 / 60.0; + + // constant representing the longest possible sequence duration + internal static readonly double kMaxTimeValue = 1000000; // more than a week's time, and within numerical precision boundaries + + /// <summary> + /// How the clip handles time outside its start and end range. + /// </summary> + public enum ClipExtrapolation + { + /// <summary> + /// No extrapolation is applied. + /// </summary> + None, + + /// <summary> + /// Hold the time at the end value of the clip. + /// </summary> + Hold, + + /// <summary> + /// Repeat time values outside the start/end range. + /// </summary> + Loop, + + /// <summary> + /// Repeat time values outside the start/end range, reversing direction at each loop + /// </summary> + PingPong, + + /// <summary> + /// Time values are passed in without modification, extending beyond the clips range + /// </summary> + Continue + }; + + /// <summary> + /// How blend curves are treated in an overlap + /// </summary> + public enum BlendCurveMode + { + /// <summary> + /// The curve is normalized against the opposing clip + /// </summary> + Auto, + + /// <summary> + /// The blend curve is fixed. + /// </summary> + Manual + }; + + internal TimelineClip(TrackAsset parent) + { + // parent clip into track + parentTrack = parent; + } + + [SerializeField] double m_Start; + [SerializeField] double m_ClipIn; + [SerializeField] Object m_Asset; + [SerializeField][FormerlySerializedAs("m_HackDuration")] double m_Duration; + [SerializeField] double m_TimeScale = 1.0; + [SerializeField] TrackAsset m_ParentTrack; + + // for mixing out scripts - default is no mix out (i.e. flat) + [SerializeField] double m_EaseInDuration; + [SerializeField] double m_EaseOutDuration; + + // the blend durations override ease in / out durations + [SerializeField] double m_BlendInDuration = -1.0f; + [SerializeField] double m_BlendOutDuration = -1.0f; + + // doubles as ease in/out and blend in/out curves + [SerializeField] AnimationCurve m_MixInCurve; + [SerializeField] AnimationCurve m_MixOutCurve; + + [SerializeField] BlendCurveMode m_BlendInCurveMode = BlendCurveMode.Auto; + [SerializeField] BlendCurveMode m_BlendOutCurveMode = BlendCurveMode.Auto; + + [SerializeField] List<string> m_ExposedParameterNames; + [SerializeField] AnimationClip m_AnimationCurves; + + [SerializeField] bool m_Recordable; + + // extrapolation + [SerializeField] ClipExtrapolation m_PostExtrapolationMode; + [SerializeField] ClipExtrapolation m_PreExtrapolationMode; + [SerializeField] double m_PostExtrapolationTime; + [SerializeField] double m_PreExtrapolationTime; + + [SerializeField] string m_DisplayName; + + /// <summary> + /// Is the clip being extrapolated before its start time? + /// </summary> + public bool hasPreExtrapolation + { + get { return m_PreExtrapolationMode != ClipExtrapolation.None && m_PreExtrapolationTime > 0; } + } + + /// <summary> + /// Is the clip being extrapolated past its end time? + /// </summary> + public bool hasPostExtrapolation + { + get { return m_PostExtrapolationMode != ClipExtrapolation.None && m_PostExtrapolationTime > 0; } + } + + /// <summary> + /// A speed multiplier for the clip; + /// </summary> + public double timeScale + { + get { return clipCaps.HasAny(ClipCaps.SpeedMultiplier) ? Math.Max(kTimeScaleMin, Math.Min(m_TimeScale, kTimeScaleMax)) : 1.0; } + set + { + UpdateDirty(m_TimeScale, value); + m_TimeScale = clipCaps.HasAny(ClipCaps.SpeedMultiplier) ? Math.Max(kTimeScaleMin, Math.Min(value, kTimeScaleMax)) : 1.0; + } + } + + /// <summary> + /// The start time, in seconds, of the clip + /// </summary> + public double start + { + get { return m_Start; } + set + { + UpdateDirty(value, m_Start); + var newValue = Math.Max(SanitizeTimeValue(value, m_Start), 0); + if (m_ParentTrack != null && m_Start != newValue) + { + m_ParentTrack.OnClipMove(); + } + m_Start = newValue; + } + } + + /// <summary> + /// The length, in seconds, of the clip + /// </summary> + public double duration + { + get { return m_Duration; } + set + { + UpdateDirty(m_Duration, value); + m_Duration = Math.Max(SanitizeTimeValue(value, m_Duration), double.Epsilon); + } + } + + /// <summary> + /// The end time, in seconds of the clip + /// </summary> + public double end + { + get { return m_Start + m_Duration; } + } + + /// <summary> + /// Local offset time of the clip. + /// </summary> + public double clipIn + { + get { return clipCaps.HasAny(ClipCaps.ClipIn) ? m_ClipIn : 0; } + set + { + UpdateDirty(m_ClipIn, value); + m_ClipIn = clipCaps.HasAny(ClipCaps.ClipIn) ? Math.Max(Math.Min(SanitizeTimeValue(value, m_ClipIn), kMaxTimeValue), 0.0) : 0; + } + } + + /// <summary> + /// The name displayed on the clip + /// </summary> + public string displayName + { + get { return m_DisplayName; } + set { m_DisplayName = value; } + } + + + /// <summary> + /// The length, in seconds, of the PlayableAsset attached to the clip. + /// </summary> + public double clipAssetDuration + { + get + { + var playableAsset = m_Asset as IPlayableAsset; + return playableAsset != null ? playableAsset.duration : double.MaxValue; + } + } + + /// <summary> + /// An animation clip containing animated properties of the attached PlayableAsset + /// </summary> + /// <remarks> + /// This is where animated clip properties are stored. + /// </remarks> + public AnimationClip curves + { + get { return m_AnimationCurves; } + internal set { m_AnimationCurves = value; } + } + + string ICurvesOwner.defaultCurvesName + { + get { return kDefaultCurvesName; } + } + + /// <summary> + /// Whether this clip contains animated properties for the attached PlayableAsset. + /// </summary> + /// <remarks> + /// This property is false if the curves property is null or if it contains no information. + /// </remarks> + public bool hasCurves + { + get { return m_AnimationCurves != null && !m_AnimationCurves.empty; } + } + + /// <summary> + /// The PlayableAsset attached to the clip. + /// </summary> + public Object asset + { + get { return m_Asset; } + set { m_Asset = value; } + } + + Object ICurvesOwner.assetOwner + { + get { return parentTrack; } + } + + TrackAsset ICurvesOwner.targetTrack + { + get { return parentTrack; } + } + + [Obsolete("underlyingAsset property is obsolete. Use asset property instead", true)] + public Object underlyingAsset + { + get { return null; } + set {} + } + + /// <summary> + /// Returns the TrackAsset to which this clip is attached. + /// </summary> + public TrackAsset parentTrack + { + get { return m_ParentTrack; } + set + { + if (m_ParentTrack == value) + return; + + if (m_ParentTrack != null) + m_ParentTrack.RemoveClip(this); + + m_ParentTrack = value; + + if (m_ParentTrack != null) + m_ParentTrack.AddClip(this); + } + } + + /// <summary> + /// The ease in duration of the timeline clip in seconds. This only applies if the start of the clip is not overlapping. + /// </summary> + public double easeInDuration + { + get { return clipCaps.HasAny(ClipCaps.Blending) ? Math.Min(Math.Max(m_EaseInDuration, 0), duration * 0.49) : 0; } + set { m_EaseInDuration = clipCaps.HasAny(ClipCaps.Blending) ? Math.Max(0, Math.Min(SanitizeTimeValue(value, m_EaseInDuration), duration * 0.49)) : 0; } + } + + /// <summary> + /// The ease out duration of the timeline clip in seconds. This only applies if the end of the clip is not overlapping. + /// </summary> + public double easeOutDuration + { + get { return clipCaps.HasAny(ClipCaps.Blending) ? Math.Min(Math.Max(m_EaseOutDuration, 0), duration * 0.49) : 0; } + set { m_EaseOutDuration = clipCaps.HasAny(ClipCaps.Blending) ? Math.Max(0, Math.Min(SanitizeTimeValue(value, m_EaseOutDuration), duration * 0.49)) : 0; } + } + + [Obsolete("Use easeOutTime instead (UnityUpgradable) -> easeOutTime", true)] + public double eastOutTime + { + get { return duration - easeOutDuration + m_Start; } + } + + /// <summary> + /// The time in seconds that the ease out begins + /// </summary> + public double easeOutTime + { + get { return duration - easeOutDuration + m_Start; } + } + + /// <summary> + /// The amount of overlap in seconds on the start of a clip. + /// </summary> + public double blendInDuration + { + get { return clipCaps.HasAny(ClipCaps.Blending) ? m_BlendInDuration : 0; } + set { m_BlendInDuration = clipCaps.HasAny(ClipCaps.Blending) ? SanitizeTimeValue(value, m_BlendInDuration) : 0; } + } + + /// <summary> + /// The amount of overlap in seconds at the end of a clip. + /// </summary> + public double blendOutDuration + { + get { return clipCaps.HasAny(ClipCaps.Blending) ? m_BlendOutDuration : 0; } + set { m_BlendOutDuration = clipCaps.HasAny(ClipCaps.Blending) ? SanitizeTimeValue(value, m_BlendOutDuration) : 0; } + } + + /// <summary> + /// The mode for calculating the blend curve of the overlap at the start of the clip + /// </summary> + public BlendCurveMode blendInCurveMode + { + get { return m_BlendInCurveMode; } + set { m_BlendInCurveMode = value; } + } + + /// <summary> + /// The mode for calculating the blend curve of the overlap at the end of the clip + /// </summary> + public BlendCurveMode blendOutCurveMode + { + get { return m_BlendOutCurveMode; } + set { m_BlendOutCurveMode = value; } + } + + /// <summary> + /// Returns whether the clip is blending in + /// </summary> + public bool hasBlendIn { get { return clipCaps.HasAny(ClipCaps.Blending) && m_BlendInDuration > 0; } } + + /// <summary> + /// Returns whether the clip is blending out + /// </summary> + public bool hasBlendOut { get { return clipCaps.HasAny(ClipCaps.Blending) && m_BlendOutDuration > 0; } } + + /// <summary> + /// The animation curve used for calculating weights during an ease in or a blend in. + /// </summary> + public AnimationCurve mixInCurve + { + get + { + // auto fix broken curves + if (m_MixInCurve == null || m_MixInCurve.length < 2) + m_MixInCurve = GetDefaultMixInCurve(); + + return m_MixInCurve; + } + set { m_MixInCurve = value; } + } + + /// <summary> + /// The amount of the clip being used for ease or blend in as a percentage + /// </summary> + public float mixInPercentage + { + get { return (float)(mixInDuration / duration); } + } + + /// <summary> + /// The amount of the clip blending or easing in, in seconds + /// </summary> + public double mixInDuration + { + get { return hasBlendIn ? blendInDuration : easeInDuration; } + } + + /// <summary> + /// The animation curve used for calculating weights during an ease out or a blend out. + /// </summary> + public AnimationCurve mixOutCurve + { + get + { + if (m_MixOutCurve == null || m_MixOutCurve.length < 2) + m_MixOutCurve = GetDefaultMixOutCurve(); + return m_MixOutCurve; + } + set { m_MixOutCurve = value; } + } + + /// <summary> + /// The time in seconds that an ease out or blend out starts + /// </summary> + public double mixOutTime + { + get { return duration - mixOutDuration + m_Start; } + } + + /// <summary> + /// The amount of the clip blending or easing out, in seconds + /// </summary> + public double mixOutDuration + { + get { return hasBlendOut ? blendOutDuration : easeOutDuration; } + } + + /// <summary> + /// The amount of the clip being used for ease or blend out as a percentage + /// </summary> + public float mixOutPercentage + { + get { return (float)(mixOutDuration / duration); } + } + + /// <summary> + /// Returns whether this clip is recordable in editor + /// </summary> + public bool recordable + { + get { return m_Recordable; } + internal set { m_Recordable = value; } + } + + [Obsolete("exposedParameter is deprecated and will be removed in a future release", true)] + public List<string> exposedParameters + { + get { return m_ExposedParameterNames ?? (m_ExposedParameterNames = new List<string>()); } + } + + /// <summary> + /// Returns the capabilities supported by this clip. + /// </summary> + public ClipCaps clipCaps + { + get + { + var clipAsset = asset as ITimelineClipAsset; + return (clipAsset != null) ? clipAsset.clipCaps : kDefaultClipCaps; + } + } + + internal int Hash() + { + return HashUtility.CombineHash(m_Start.GetHashCode(), + m_Duration.GetHashCode(), + m_TimeScale.GetHashCode(), + m_ClipIn.GetHashCode(), + ((int)m_PreExtrapolationMode).GetHashCode(), + ((int)m_PostExtrapolationMode).GetHashCode()); + } + + /// <summary> + /// Given a time, returns the weight from the mix out + /// </summary> + /// <param name="time">Time (relative to the timeline)</param> + /// <returns></returns> + public float EvaluateMixOut(double time) + { + if (!clipCaps.HasAny(ClipCaps.Blending)) + return 1.0f; + + if (mixOutDuration > Mathf.Epsilon) + { + var perc = (float)(time - mixOutTime) / (float)mixOutDuration; + perc = Mathf.Clamp01(mixOutCurve.Evaluate(perc)); + return perc; + } + return 1.0f; + } + + /// <summary> + /// Given a time, returns the weight from the mix in + /// </summary> + /// <param name="time">Time (relative to the timeline)</param> + /// <returns></returns> + public float EvaluateMixIn(double time) + { + if (!clipCaps.HasAny(ClipCaps.Blending)) + return 1.0f; + + if (mixInDuration > Mathf.Epsilon) + { + var perc = (float)(time - m_Start) / (float)mixInDuration; + perc = Mathf.Clamp01(mixInCurve.Evaluate(perc)); + return perc; + } + return 1.0f; + } + + static AnimationCurve GetDefaultMixInCurve() + { + return AnimationCurve.EaseInOut(0, 0, 1, 1); + } + + static AnimationCurve GetDefaultMixOutCurve() + { + return AnimationCurve.EaseInOut(0, 1, 1, 0); + } + + /// <summary> + /// Converts from global time to a clips local time. + /// </summary> + /// <param name="time">time relative to the timeline</param> + /// <returns> + /// The local time with extrapolation applied + /// </returns> + public double ToLocalTime(double time) + { + if (time < 0) + return time; + + // handle Extrapolation + if (IsPreExtrapolatedTime(time)) + time = GetExtrapolatedTime(time - m_Start, m_PreExtrapolationMode, m_Duration); + else if (IsPostExtrapolatedTime(time)) + time = GetExtrapolatedTime(time - m_Start, m_PostExtrapolationMode, m_Duration); + else + time -= m_Start; + + // handle looping and time scale within the clip + time *= timeScale; + time += clipIn; + + return time; + } + + /// <summary> + /// Converts from global time to local time of the clip + /// </summary> + /// <param name="time">The time relative to the timeline</param> + /// <returns>The local time, ignoring any extrapolation or bounds</returns> + public double ToLocalTimeUnbound(double time) + { + return (time - m_Start) * timeScale + clipIn; + } + + /// <summary> + /// Converts from local time of the clip to global time + /// </summary> + /// <param name="time">Time relative to the clip</param> + /// <returns>The time relative to the timeline</returns> + internal double FromLocalTimeUnbound(double time) + { + return (time - clipIn) / timeScale + m_Start; + } + + /// <summary> + /// If this contains an animation asset, returns the animation clip attached. Otherwise returns null. + /// </summary> + public AnimationClip animationClip + { + get + { + if (m_Asset == null) + return null; + + var playableAsset = m_Asset as AnimationPlayableAsset; + return playableAsset != null ? playableAsset.clip : null; + } + } + + static double SanitizeTimeValue(double value, double defaultValue) + { + if (double.IsInfinity(value) || double.IsNaN(value)) + { + Debug.LogError("Invalid time value assigned"); + return defaultValue; + } + + return Math.Max(-kMaxTimeValue, Math.Min(kMaxTimeValue, value)); + } + + /// <summary> + /// Returns whether the clip is being extrapolated past the end time. + /// </summary> + public ClipExtrapolation postExtrapolationMode + { + get { return clipCaps.HasAny(ClipCaps.Extrapolation) ? m_PostExtrapolationMode : ClipExtrapolation.None; } + internal set { m_PostExtrapolationMode = clipCaps.HasAny(ClipCaps.Extrapolation) ? value : ClipExtrapolation.None; } + } + + /// <summary> + /// Returns whether the clip is being extrapolated before the start time. + /// </summary> + public ClipExtrapolation preExtrapolationMode + { + get { return clipCaps.HasAny(ClipCaps.Extrapolation) ? m_PreExtrapolationMode : ClipExtrapolation.None; } + internal set { m_PreExtrapolationMode = clipCaps.HasAny(ClipCaps.Extrapolation) ? value : ClipExtrapolation.None; } + } + + internal void SetPostExtrapolationTime(double time) + { + m_PostExtrapolationTime = time; + } + + internal void SetPreExtrapolationTime(double time) + { + m_PreExtrapolationTime = time; + } + + /// <summary> + /// Given a time, returns whether it falls within the clips extrapolation + /// </summary> + /// <param name="sequenceTime">The time relative to the timeline</param> + public bool IsExtrapolatedTime(double sequenceTime) + { + return IsPreExtrapolatedTime(sequenceTime) || IsPostExtrapolatedTime(sequenceTime); + } + + /// <summary> + /// Given a time, returns whether it falls within the clip pre-extrapolation + /// </summary> + /// <param name="sequenceTime">The time relative to the timeline</param> + public bool IsPreExtrapolatedTime(double sequenceTime) + { + return preExtrapolationMode != ClipExtrapolation.None && + sequenceTime < m_Start && sequenceTime >= m_Start - m_PreExtrapolationTime; + } + + /// <summary> + /// Given a time, returns whether it falls within the clip post-extrapolation + /// </summary> + /// <param name="sequenceTime">The time relative to the timeline</param> + public bool IsPostExtrapolatedTime(double sequenceTime) + { + return postExtrapolationMode != ClipExtrapolation.None && + (sequenceTime > end) && (sequenceTime - end < m_PostExtrapolationTime); + } + + /// <summary> + /// The start time of the clip, accounting for pre-extrapolation + /// </summary> + public double extrapolatedStart + { + get + { + if (m_PreExtrapolationMode != ClipExtrapolation.None) + return m_Start - m_PreExtrapolationTime; + + return m_Start; + } + } + + /// <summary> + /// The length of the clip in seconds, including extrapolation. + /// </summary> + public double extrapolatedDuration + { + get + { + double length = m_Duration; + + if (m_PostExtrapolationMode != ClipExtrapolation.None) + length += Math.Min(m_PostExtrapolationTime, kMaxTimeValue); + + if (m_PreExtrapolationMode != ClipExtrapolation.None) + length += m_PreExtrapolationTime; + + return length; + } + } + + static double GetExtrapolatedTime(double time, ClipExtrapolation mode, double duration) + { + if (duration == 0) + return 0; + + switch (mode) + { + case ClipExtrapolation.None: + break; + + case ClipExtrapolation.Loop: + if (time < 0) + time = duration - (-time % duration); + else if (time > duration) + time %= duration; + break; + + case ClipExtrapolation.Hold: + if (time < 0) + return 0; + if (time > duration) + return duration; + break; + + case ClipExtrapolation.PingPong: + if (time < 0) + { + time = duration * 2 - (-time % (duration * 2)); + time = duration - Math.Abs(time - duration); + } + else + { + time = time % (duration * 2.0); + time = duration - Math.Abs(time - duration); + } + break; + + case ClipExtrapolation.Continue: + break; + } + return time; + } + + /// <summary> + /// Creates an AnimationClip to store animated properties for the attached PlayableAsset. + /// </summary> + /// <remarks> + /// If curves already exists for this clip, this method produces no result regardless of the + /// value specified for curvesClipName. + /// </remarks> + /// <remarks> + /// When used from the editor, this method attempts to save the created curves clip to the TimelineAsset. + /// The TimelineAsset must already exist in the AssetDatabase to save the curves clip. If the TimelineAsset + /// does not exist, the curves clip is still created but it is not saved. + /// </remarks> + /// <param name="curvesClipName"> + /// The name of the AnimationClip to create. + /// This method does not ensure unique names. If you want a unique clip name, you must provide one. + /// See ObjectNames.GetUniqueName for information on a method that creates unique names. + /// </param> + public void CreateCurves(string curvesClipName) + { + if (m_AnimationCurves != null) + return; + + m_AnimationCurves = TimelineCreateUtilities.CreateAnimationClipForTrack(string.IsNullOrEmpty(curvesClipName) ? kDefaultCurvesName : curvesClipName, parentTrack, true); + } + + void ISerializationCallbackReceiver.OnBeforeSerialize() + { + m_Version = k_LatestVersion; + } + + void ISerializationCallbackReceiver.OnAfterDeserialize() + { + if (m_Version < k_LatestVersion) + { + UpgradeToLatestVersion(); + } + } + + /// <summary> + /// Outputs a more readable representation of the timeline clip as a string + /// </summary> + /// <returns></returns> + public override string ToString() + { + return UnityString.Format("{0} ({1:F2}, {2:F2}):{3:F2} | {4}", displayName, start, end, clipIn, parentTrack); + } + +#if UNITY_EDITOR + internal int DirtyIndex { get; private set; } + internal void MarkDirty() + { + DirtyIndex++; + } + + void UpdateDirty(double oldValue, double newValue) + { + if (oldValue != newValue) + DirtyIndex++; + } + +#else + void UpdateDirty(double oldValue, double newValue) {} +#endif + }; +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelineClip.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelineClip.cs.meta new file mode 100644 index 0000000..ded129f --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelineClip.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 65f3a4c67e4927a478b7036bae1da0e3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelinePlayable.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelinePlayable.cs new file mode 100644 index 0000000..f028a7a --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelinePlayable.cs @@ -0,0 +1,310 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Animations; +using UnityEngine.Audio; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + // Generic evaluation callback called after all the clips have been processed + internal interface ITimelineEvaluateCallback + { + void Evaluate(); + } + + +#if UNITY_EDITOR + /// <summary> + /// This Rebalancer class ensures that the interval tree structures stays balance regardless of whether the intervals inside change. + /// </summary> + class IntervalTreeRebalancer + { + private IntervalTree<RuntimeElement> m_Tree; + public IntervalTreeRebalancer(IntervalTree<RuntimeElement> tree) + { + m_Tree = tree; + } + + public bool Rebalance() + { + m_Tree.UpdateIntervals(); + return m_Tree.dirty; + } + } +#endif + + // The TimelinePlayable Playable + // This is the actual runtime playable that gets evaluated as part of a playable graph. + // It "compiles" a list of tracks into an IntervalTree of Runtime clips. + // At each frame, it advances time, then fetches the "intersection: of various time interval + // using the interval tree. + // Finally, on each intersecting clip, it will calculate each clips' local time, as well as + // blend weight and set them accordingly + + + /// <summary> + /// The root Playable generated by timeline. + /// </summary> + public class TimelinePlayable : PlayableBehaviour + { + private IntervalTree<RuntimeElement> m_IntervalTree = new IntervalTree<RuntimeElement>(); + private List<RuntimeElement> m_ActiveClips = new List<RuntimeElement>(); + private List<RuntimeElement> m_CurrentListOfActiveClips; + private int m_ActiveBit = 0; + + private List<ITimelineEvaluateCallback> m_EvaluateCallbacks = new List<ITimelineEvaluateCallback>(); + + private Dictionary<TrackAsset, Playable> m_PlayableCache = new Dictionary<TrackAsset, Playable>(); + + internal static bool muteAudioScrubbing = true; + +#if UNITY_EDITOR + private IntervalTreeRebalancer m_Rebalancer; +#endif + /// <summary> + /// Creates an instance of a Timeline + /// </summary> + /// <param name="graph">The playable graph to inject the timeline.</param> + /// <param name="tracks">The list of tracks to compile</param> + /// <param name="go">The GameObject that initiated the compilation</param> + /// <param name="autoRebalance">In the editor, whether the graph should account for the possibility of changing clip times</param> + /// <param name="createOutputs">Whether to create PlayableOutputs in the graph</param> + /// <returns>A subgraph with the playable containing a TimelinePlayable behaviour as the root</returns> + public static ScriptPlayable<TimelinePlayable> Create(PlayableGraph graph, IEnumerable<TrackAsset> tracks, GameObject go, bool autoRebalance, bool createOutputs) + { + if (tracks == null) + throw new ArgumentNullException("Tracks list is null", "tracks"); + + if (go == null) + throw new ArgumentNullException("GameObject parameter is null", "go"); + + var playable = ScriptPlayable<TimelinePlayable>.Create(graph); + playable.SetTraversalMode(PlayableTraversalMode.Passthrough); + var sequence = playable.GetBehaviour(); + sequence.Compile(graph, playable, tracks, go, autoRebalance, createOutputs); + return playable; + } + + /// <summary> + /// Compiles the subgraph of this timeline + /// </summary> + /// <param name="graph">The playable graph to inject the timeline.</param> + /// <param name="timelinePlayable"></param> + /// <param name="tracks">The list of tracks to compile</param> + /// <param name="go">The GameObject that initiated the compilation</param> + /// <param name="autoRebalance">In the editor, whether the graph should account for the possibility of changing clip times</param> + /// <param name="createOutputs">Whether to create PlayableOutputs in the graph</param> + public void Compile(PlayableGraph graph, Playable timelinePlayable, IEnumerable<TrackAsset> tracks, GameObject go, bool autoRebalance, bool createOutputs) + { + if (tracks == null) + throw new ArgumentNullException("Tracks list is null", "tracks"); + + if (go == null) + throw new ArgumentNullException("GameObject parameter is null", "go"); + + var outputTrackList = new List<TrackAsset>(tracks); + var maximumNumberOfIntersections = outputTrackList.Count * 2 + outputTrackList.Count; // worse case: 2 overlapping clips per track + each track + m_CurrentListOfActiveClips = new List<RuntimeElement>(maximumNumberOfIntersections); + m_ActiveClips = new List<RuntimeElement>(maximumNumberOfIntersections); + + m_EvaluateCallbacks.Clear(); + m_PlayableCache.Clear(); + + CompileTrackList(graph, timelinePlayable, outputTrackList, go, createOutputs); + +#if UNITY_EDITOR + if (autoRebalance) + { + m_Rebalancer = new IntervalTreeRebalancer(m_IntervalTree); + } +#endif + } + + private void CompileTrackList(PlayableGraph graph, Playable timelinePlayable, IEnumerable<TrackAsset> tracks, GameObject go, bool createOutputs) + { + foreach (var track in tracks) + { + if (!track.IsCompilable()) + continue; + + if (!m_PlayableCache.ContainsKey(track)) + { + track.SortClips(); + CreateTrackPlayable(graph, timelinePlayable, track, go, createOutputs); + } + } + } + + void CreateTrackOutput(PlayableGraph graph, TrackAsset track, GameObject go, Playable playable, int port) + { + if (track.isSubTrack) + return; + + var bindings = track.outputs; + foreach (var binding in bindings) + { + var playableOutput = binding.CreateOutput(graph); + playableOutput.SetReferenceObject(binding.sourceObject); + playableOutput.SetSourcePlayable(playable, port); + playableOutput.SetWeight(1.0f); + + // only apply this on our animation track + if (track as AnimationTrack != null) + { + EvaluateWeightsForAnimationPlayableOutput(track, (AnimationPlayableOutput)playableOutput); +#if UNITY_EDITOR + if (!Application.isPlaying) + EvaluateAnimationPreviewUpdateCallback(track, (AnimationPlayableOutput)playableOutput); +#endif + } + if (playableOutput.IsPlayableOutputOfType<AudioPlayableOutput>()) + ((AudioPlayableOutput)playableOutput).SetEvaluateOnSeek(!muteAudioScrubbing); + + // If the track is the timeline marker track, assume binding is the PlayableDirector + if (track.timelineAsset.markerTrack == track) + { + var director = go.GetComponent<PlayableDirector>(); + playableOutput.SetUserData(director); + foreach (var c in go.GetComponents<INotificationReceiver>()) + { + playableOutput.AddNotificationReceiver(c); + } + } + } + } + + void EvaluateWeightsForAnimationPlayableOutput(TrackAsset track, AnimationPlayableOutput animOutput) + { + m_EvaluateCallbacks.Add(new AnimationOutputWeightProcessor(animOutput)); + } + + void EvaluateAnimationPreviewUpdateCallback(TrackAsset track, AnimationPlayableOutput animOutput) + { + m_EvaluateCallbacks.Add(new AnimationPreviewUpdateCallback(animOutput)); + } + + private static Playable CreatePlayableGraph(PlayableGraph graph, TrackAsset asset, GameObject go, IntervalTree<RuntimeElement> tree, Playable timelinePlayable) + { + return asset.CreatePlayableGraph(graph, go, tree, timelinePlayable); + } + + private Playable CreateTrackPlayable(PlayableGraph graph, Playable timelinePlayable, TrackAsset track, GameObject go, bool createOutputs) + { + if (!track.IsCompilable()) // where parents are not compilable (group tracks) + return timelinePlayable; + + Playable playable; + if (m_PlayableCache.TryGetValue(track, out playable)) + return playable; + + if (track.name == "root") + return timelinePlayable; + + TrackAsset parentActor = track.parent as TrackAsset; + var parentPlayable = parentActor != null ? CreateTrackPlayable(graph, timelinePlayable, parentActor, go, createOutputs) : timelinePlayable; + var actorPlayable = CreatePlayableGraph(graph, track, go, m_IntervalTree, timelinePlayable); + bool connected = false; + + if (!actorPlayable.IsValid()) + { + // if a track says it's compilable, but returns Playable.Null, that can screw up the whole graph. + throw new InvalidOperationException(track.name + "(" + track.GetType() + ") did not produce a valid playable. Use the compilable property to indicate whether the track is valid for processing"); + } + + + // Special case for animation tracks + if (parentPlayable.IsValid() && actorPlayable.IsValid()) + { + int port = parentPlayable.GetInputCount(); + parentPlayable.SetInputCount(port + 1); + connected = graph.Connect(actorPlayable, 0, parentPlayable, port); + parentPlayable.SetInputWeight(port, 1.0f); + } + + if (createOutputs && connected) + { + CreateTrackOutput(graph, track, go, parentPlayable, parentPlayable.GetInputCount() - 1); + } + + CacheTrack(track, actorPlayable, connected ? (parentPlayable.GetInputCount() - 1) : -1, parentPlayable); + return actorPlayable; + } + + /// <summary> + /// Overridden to handle synchronizing time on the timeline instance. + /// </summary> + /// <param name="playable">The Playable that owns the current PlayableBehaviour.</param> + /// <param name="info">A FrameData structure that contains information about the current frame context.</param> + public override void PrepareFrame(Playable playable, FrameData info) + { +#if UNITY_EDITOR + if (m_Rebalancer != null) + m_Rebalancer.Rebalance(); +#endif + + // force seek if we are being evaluated + // or if our time has jumped. This is used to + // resynchronize + Evaluate(playable, info); + } + + private void Evaluate(Playable playable, FrameData frameData) + { + if (m_IntervalTree == null) + return; + + double localTime = playable.GetTime(); + m_ActiveBit = m_ActiveBit == 0 ? 1 : 0; + + m_CurrentListOfActiveClips.Clear(); + m_IntervalTree.IntersectsWith(DiscreteTime.GetNearestTick(localTime), m_CurrentListOfActiveClips); + + foreach (var c in m_CurrentListOfActiveClips) + { + c.intervalBit = m_ActiveBit; + if (frameData.timeLooped) + c.Reset(); + } + + // all previously active clips having a different intervalBit flag are not + // in the current intersection, therefore are considered becoming disabled at this frame + var timelineEnd = playable.GetDuration(); + foreach (var c in m_ActiveClips) + { + if (c.intervalBit != m_ActiveBit) + { + var clipEnd = (double)DiscreteTime.FromTicks(c.intervalEnd); + var time = frameData.timeLooped ? Math.Min(clipEnd, timelineEnd) : Math.Min(localTime, clipEnd); + c.EvaluateAt(time, frameData); + c.enable = false; + } + } + + m_ActiveClips.Clear(); + // case 998642 - don't use m_ActiveClips.AddRange, as in 4.6 .Net scripting it causes GC allocs + for (var a = 0; a < m_CurrentListOfActiveClips.Count; a++) + { + m_CurrentListOfActiveClips[a].EvaluateAt(localTime, frameData); + m_ActiveClips.Add(m_CurrentListOfActiveClips[a]); + } + + int count = m_EvaluateCallbacks.Count; + for (int i = 0; i < count; i++) + { + m_EvaluateCallbacks[i].Evaluate(); + } + } + + private void CacheTrack(TrackAsset track, Playable playable, int port, Playable parent) + { + m_PlayableCache[track] = playable; + } + + //necessary to build on AOT platforms + static void ForAOTCompilationOnly() + { + new List<IntervalTree<RuntimeElement>.Entry>(); + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelinePlayable.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelinePlayable.cs.meta new file mode 100644 index 0000000..cb373dd --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TimelinePlayable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 80b10e1c58509a449a3c5aecc07d4455 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TrackAsset.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TrackAsset.cs new file mode 100644 index 0000000..cc0f607 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TrackAsset.cs @@ -0,0 +1,1264 @@ +using System; +using System.Collections.Generic; +using System.IO; +using UnityEngine.Animations; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// A PlayableAsset representing a track inside a timeline. + /// </summary> + [Serializable] + [IgnoreOnPlayableTrack] + public abstract partial class TrackAsset : PlayableAsset, IPropertyPreview, ICurvesOwner + { + // Internal caches used to avoid memory allocation during graph construction + private struct TransientBuildData + { + public List<TrackAsset> trackList; + public List<TimelineClip> clipList; + public List<IMarker> markerList; + + public static TransientBuildData Create() + { + return new TransientBuildData() + { + trackList = new List<TrackAsset>(20), + clipList = new List<TimelineClip>(500), + markerList = new List<IMarker>(100), + }; + } + + public void Clear() + { + trackList.Clear(); + clipList.Clear(); + markerList.Clear(); + } + } + + private static TransientBuildData s_BuildData = TransientBuildData.Create(); + + internal const string kDefaultCurvesName = "Track Parameters"; + + internal static event Action<TimelineClip, GameObject, Playable> OnClipPlayableCreate; + internal static event Action<TrackAsset, GameObject, Playable> OnTrackAnimationPlayableCreate; + + [SerializeField, HideInInspector] bool m_Locked; + [SerializeField, HideInInspector] bool m_Muted; + [SerializeField, HideInInspector] string m_CustomPlayableFullTypename = string.Empty; + [SerializeField, HideInInspector] AnimationClip m_Curves; + [SerializeField, HideInInspector] PlayableAsset m_Parent; + [SerializeField, HideInInspector] List<ScriptableObject> m_Children; + + [NonSerialized] int m_ItemsHash; + [NonSerialized] TimelineClip[] m_ClipsCache; + + DiscreteTime m_Start; + DiscreteTime m_End; + bool m_CacheSorted; + bool? m_SupportsNotifications; + + static TrackAsset[] s_EmptyCache = new TrackAsset[0]; + IEnumerable<TrackAsset> m_ChildTrackCache; + + static Dictionary<Type, TrackBindingTypeAttribute> s_TrackBindingTypeAttributeCache = new Dictionary<Type, TrackBindingTypeAttribute>(); + + [SerializeField, HideInInspector] protected internal List<TimelineClip> m_Clips = new List<TimelineClip>(); + + [SerializeField, HideInInspector] MarkerList m_Markers = new MarkerList(0); + +#if UNITY_EDITOR + internal int DirtyIndex { get; private set; } + internal void MarkDirty() + { + DirtyIndex++; + foreach (var clip in GetClips()) + { + if (clip != null) + clip.MarkDirty(); + } + } + +#endif + + /// <summary> + /// The start time, in seconds, of this track + /// </summary> + public double start + { + get + { + UpdateDuration(); + return (double)m_Start; + } + } + + /// <summary> + /// The end time, in seconds, of this track + /// </summary> + public double end + { + get + { + UpdateDuration(); + return (double)m_End; + } + } + + /// <summary> + /// The length, in seconds, of this track + /// </summary> + public sealed override double duration + { + get + { + UpdateDuration(); + return (double)(m_End - m_Start); + } + } + + /// <summary> + /// Whether the track is muted or not. + /// </summary> + /// <remarks> + /// A muted track is excluded from the generated PlayableGraph + /// </remarks> + public bool muted + { + get { return m_Muted; } + set { m_Muted = value; } + } + + /// <summary> + /// The muted state of a track. + /// </summary> + /// <remarks> + /// A track is also muted when one of its parent tracks are muted. + /// </remarks> + public bool mutedInHierarchy + { + get + { + if (muted) + return true; + + TrackAsset p = this; + while (p.parent as TrackAsset != null) + { + p = (TrackAsset)p.parent; + if (p as GroupTrack != null) + return p.mutedInHierarchy; + } + + return false; + } + } + + /// <summary> + /// The TimelineAsset that this track belongs to. + /// </summary> + public TimelineAsset timelineAsset + { + get + { + var node = this; + while (node != null) + { + if (node.parent == null) + return null; + + var seq = node.parent as TimelineAsset; + if (seq != null) + return seq; + + node = node.parent as TrackAsset; + } + return null; + } + } + + /// <summary> + /// The owner of this track. + /// </summary> + /// <remarks> + /// If this track is a subtrack, the parent is a TrackAsset. Otherwise the parent is a TimelineAsset. + /// </remarks> + public PlayableAsset parent + { + get { return m_Parent; } + internal set { m_Parent = value; } + } + + /// <summary> + /// A list of clips owned by this track + /// </summary> + /// <returns>Returns an enumerable list of clips owned by the track.</returns> + public IEnumerable<TimelineClip> GetClips() + { + return clips; + } + + internal TimelineClip[] clips + { + get + { + if (m_Clips == null) + m_Clips = new List<TimelineClip>(); + + if (m_ClipsCache == null) + { + m_CacheSorted = false; + m_ClipsCache = m_Clips.ToArray(); + } + + return m_ClipsCache; + } + } + + /// <summary> + /// Whether this track is considered empty. + /// </summary> + /// <remarks> + /// A track is considered empty when it does not contain a TimelineClip, Marker, or Curve. + /// </remarks> + /// <remarks> + /// Empty tracks are not included in the playable graph. + /// </remarks> + public virtual bool isEmpty + { + get { return !hasClips && !hasCurves && GetMarkerCount() == 0; } + } + + /// <summary> + /// Whether this track contains any TimelineClip. + /// </summary> + public bool hasClips + { + get { return m_Clips != null && m_Clips.Count != 0; } + } + + /// <summary> + /// Whether this track contains animated properties for the attached PlayableAsset. + /// </summary> + /// <remarks> + /// This property is false if the curves property is null or if it contains no information. + /// </remarks> + public bool hasCurves + { + get { return m_Curves != null && !m_Curves.empty; } + } + + /// <summary> + /// Returns whether this track is a subtrack + /// </summary> + public bool isSubTrack + { + get + { + var owner = parent as TrackAsset; + return owner != null && owner.GetType() == GetType(); + } + } + + + /// <summary> + /// Returns a description of the PlayableOutputs that will be created by this track. + /// </summary> + public override IEnumerable<PlayableBinding> outputs + { + get + { + TrackBindingTypeAttribute attribute; + if (!s_TrackBindingTypeAttributeCache.TryGetValue(GetType(), out attribute)) + { + attribute = (TrackBindingTypeAttribute)Attribute.GetCustomAttribute(GetType(), typeof(TrackBindingTypeAttribute)); + s_TrackBindingTypeAttributeCache.Add(GetType(), attribute); + } + + var trackBindingType = attribute != null ? attribute.type : null; + yield return ScriptPlayableBinding.Create(name, this, trackBindingType); + } + } + + /// <summary> + /// The list of subtracks or child tracks attached to this track. + /// </summary> + /// <returns>Returns an enumerable list of child tracks owned directly by this track.</returns> + /// <remarks> + /// In the case of GroupTracks, this returns all tracks contained in the group. This will return the all subtracks or override tracks, if supported by the track. + /// </remarks> + public IEnumerable<TrackAsset> GetChildTracks() + { + UpdateChildTrackCache(); + return m_ChildTrackCache; + } + + internal string customPlayableTypename + { + get { return m_CustomPlayableFullTypename; } + set { m_CustomPlayableFullTypename = value; } + } + + /// <summary> + /// An animation clip storing animated properties of the attached PlayableAsset + /// </summary> + public AnimationClip curves + { + get { return m_Curves; } + internal set { m_Curves = value; } + } + + string ICurvesOwner.defaultCurvesName + { + get { return kDefaultCurvesName; } + } + + Object ICurvesOwner.asset + { + get { return this; } + } + + Object ICurvesOwner.assetOwner + { + get { return timelineAsset; } + } + + TrackAsset ICurvesOwner.targetTrack + { + get { return this; } + } + + // for UI where we need to detect 'null' objects + internal List<ScriptableObject> subTracksObjects + { + get { return m_Children; } + } + + /// <summary> + /// The local locked state of the track. + /// </summary> + /// <remarks> + /// Note that locking a track only affects operations in the Timeline Editor. It does not prevent other API calls from changing a track or it's clips. + /// + /// This returns or sets the local locked state of the track. A track may still be locked for editing because one or more of it's parent tracks in the hierarchy is locked. Use lockedInHierarchy to test if a track is locked because of it's own locked state or because of a parent tracks locked state. + /// </remarks> + public bool locked + { + get { return m_Locked; } + set { m_Locked = value; } + } + + /// <summary> + /// The locked state of a track. (RO) + /// </summary> + /// <remarks> + /// Note that locking a track only affects operations in the Timeline Editor. It does not prevent other API calls from changing a track or it's clips. + /// + /// This indicates whether a track is locked in the Timeline Editor because either it's locked property is enabled or a parent track is locked. + /// </remarks> + public bool lockedInHierarchy + { + get + { + if (locked) + return true; + + TrackAsset p = this; + while (p.parent as TrackAsset != null) + { + p = (TrackAsset)p.parent; + if (p as GroupTrack != null) + return p.lockedInHierarchy; + } + + return false; + } + } + + /// <summary> + /// Indicates if a track accepts markers that implement <see cref="UnityEngine.Playables.INotification"/>. + /// </summary> + /// <remarks> + /// Only tracks with a bound object of type <see cref="UnityEngine.GameObject"/> or <see cref="UnityEngine.Component"/> can accept notifications. + /// </remarks> + public bool supportsNotifications + { + get + { + if (!m_SupportsNotifications.HasValue) + { + m_SupportsNotifications = NotificationUtilities.TrackTypeSupportsNotifications(GetType()); + } + + return m_SupportsNotifications.Value; + } + } + + void __internalAwake() //do not use OnEnable, since users will want it to initialize their class + { + if (m_Clips == null) + m_Clips = new List<TimelineClip>(); + + m_ChildTrackCache = null; + if (m_Children == null) + m_Children = new List<ScriptableObject>(); +#if UNITY_EDITOR + // validate the array. DON'T remove Unity null objects, just actual null objects + for (int i = m_Children.Count - 1; i >= 0; i--) + { + object o = m_Children[i]; + if (o == null) + { + Debug.LogWarning("Empty child track found while loading timeline. It will be removed."); + m_Children.RemoveAt(i); + } + } +#endif + } + + /// <summary> + /// Creates an AnimationClip to store animated properties for the attached PlayableAsset. + /// </summary> + /// <remarks> + /// If curves already exists for this track, this method produces no result regardless of + /// the value specified for curvesClipName. + /// </remarks> + /// <remarks> + /// When used from the editor, this method attempts to save the created curves clip to the TimelineAsset. + /// The TimelineAsset must already exist in the AssetDatabase to save the curves clip. If the TimelineAsset + /// does not exist, the curves clip is still created but it is not saved. + /// </remarks> + /// <param name="curvesClipName"> + /// The name of the AnimationClip to create. + /// This method does not ensure unique names. If you want a unique clip name, you must provide one. + /// See ObjectNames.GetUniqueName for information on a method that creates unique names. + /// </param> + public void CreateCurves(string curvesClipName) + { + if (m_Curves != null) + return; + + m_Curves = TimelineCreateUtilities.CreateAnimationClipForTrack(string.IsNullOrEmpty(curvesClipName) ? kDefaultCurvesName : curvesClipName, this, true); + } + + /// <summary> + /// Creates a mixer used to blend playables generated by clips on the track. + /// </summary> + /// <param name="graph">The graph to inject playables into</param> + /// <param name="go">The GameObject that requested the graph.</param> + /// <param name="inputCount">The number of playables from clips that will be inputs to the returned mixer</param> + /// <returns>A handle to the [[Playable]] representing the mixer.</returns> + /// <remarks> + /// Override this method to provide a custom playable for mixing clips on a graph. + /// </remarks> + public virtual Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount) + { + return Playable.Create(graph, inputCount); + } + + /// <summary> + /// Overrides PlayableAsset.CreatePlayable(). Not used in Timeline. + /// </summary> + public sealed override Playable CreatePlayable(PlayableGraph graph, GameObject go) + { + return Playable.Null; + } + + /// <summary> + /// Creates a TimelineClip on this track. + /// </summary> + /// <returns>Returns a new TimelineClip that is attached to the track.</returns> + /// <remarks> + /// The type of the playable asset attached to the clip is determined by TrackClip attributes that decorate the TrackAsset derived class + /// </remarks> + public TimelineClip CreateDefaultClip() + { + var trackClipTypeAttributes = GetType().GetCustomAttributes(typeof(TrackClipTypeAttribute), true); + Type playableAssetType = null; + foreach (var trackClipTypeAttribute in trackClipTypeAttributes) + { + var attribute = trackClipTypeAttribute as TrackClipTypeAttribute; + if (attribute != null && typeof(IPlayableAsset).IsAssignableFrom(attribute.inspectedType) && typeof(ScriptableObject).IsAssignableFrom(attribute.inspectedType)) + { + playableAssetType = attribute.inspectedType; + break; + } + } + + if (playableAssetType == null) + { + Debug.LogWarning("Cannot create a default clip for type " + GetType()); + return null; + } + return CreateAndAddNewClipOfType(playableAssetType); + } + + /// <summary> + /// Creates a clip on the track with a playable asset attached, whose derived type is specified by T + /// </summary> + /// <typeparam name="T">A PlayableAsset derived type</typeparam> + /// <returns>Returns a TimelineClip whose asset is of type T</returns> + /// <remarks> + /// Throws an InvalidOperationException if the specified type is not supported by the track. + /// Supported types are determined by TrackClip attributes that decorate the TrackAsset derived class + /// </remarks> + public TimelineClip CreateClip<T>() where T : ScriptableObject, IPlayableAsset + { + return CreateClip(typeof(T)); + } + + /// <summary> + /// Creates a marker of the requested type, at a specific time, and adds the marker to the current asset. + /// </summary> + /// <param name="type">The type of marker.</param> + /// <param name="time">The time where the marker is created.</param> + /// <returns>Returns the instance of the created marker.</returns> + /// <remarks> + /// All markers that implement IMarker and inherit from <see cref="UnityEngine.ScriptableObject"/> are supported. + /// Markers that implement the INotification interface cannot be added to tracks that do not support notifications. + /// CreateMarker will throw an <code>InvalidOperationException</code> with tracks that do not support notifications if <code>type</code> implements the INotification interface. + /// </remarks> + /// <seealso cref="UnityEngine.Timeline.Marker"/> + /// <seealso cref="UnityEngine.Timeline.TrackAsset.supportsNotifications"/> + public IMarker CreateMarker(Type type, double time) + { + return m_Markers.CreateMarker(type, time, this); + } + + /// <summary> + /// Creates a marker of the requested type, at a specific time, and adds the marker to the current asset. + /// </summary> + /// <param name="time">The time where the marker is created.</param> + /// <returns>Returns the instance of the created marker.</returns> + /// <remarks> + /// All markers that implement IMarker and inherit from <see cref="UnityEngine.ScriptableObject"/> are supported. + /// CreateMarker will throw an <code>InvalidOperationException</code> with tracks that do not support notifications if <code>T</code> implements the INotification interface. + /// </remarks> + /// <seealso cref="UnityEngine.Timeline.Marker"/> + /// <seealso cref="UnityEngine.Timeline.TrackAsset.supportsNotifications"/> + public T CreateMarker<T>(double time) where T : ScriptableObject, IMarker + { + return (T)CreateMarker(typeof(T), time); + } + + /// <summary> + /// Removes a marker from the current asset. + /// </summary> + /// <param name="marker">The marker instance to be removed.</param> + /// <returns>Returns true if the marker instance was successfully removed. Returns false otherwise.</returns> + public bool DeleteMarker(IMarker marker) + { + return m_Markers.Remove(marker); + } + + /// <summary> + /// Returns an enumerable list of markers on the current asset. + /// </summary> + /// <returns>The list of markers on the asset. + /// </returns> + public IEnumerable<IMarker> GetMarkers() + { + return m_Markers.GetMarkers(); + } + + /// <summary> + /// Returns the number of markers on the current asset. + /// </summary> + /// <returns>The number of markers.</returns> + public int GetMarkerCount() + { + return m_Markers.Count; + } + + /// <summary> + /// Returns the marker at a given position, on the current asset. + /// </summary> + /// <param name="idx">The index of the marker to be returned.</param> + /// <returns>The marker.</returns> + /// <remarks>The ordering of the markers is not guaranteed. + /// </remarks> + public IMarker GetMarker(int idx) + { + return m_Markers[idx]; + } + + internal TimelineClip CreateClip(System.Type requestedType) + { + if (ValidateClipType(requestedType)) + return CreateAndAddNewClipOfType(requestedType); + + throw new InvalidOperationException("Clips of type " + requestedType + " are not permitted on tracks of type " + GetType()); + } + + internal TimelineClip CreateAndAddNewClipOfType(Type requestedType) + { + var newClip = CreateClipOfType(requestedType); + AddClip(newClip); + return newClip; + } + + internal TimelineClip CreateClipOfType(Type requestedType) + { + if (!ValidateClipType(requestedType)) + throw new System.InvalidOperationException("Clips of type " + requestedType + " are not permitted on tracks of type " + GetType()); + + var playableAsset = CreateInstance(requestedType); + if (playableAsset == null) + { + throw new System.InvalidOperationException("Could not create an instance of the ScriptableObject type " + requestedType.Name); + } + playableAsset.name = requestedType.Name; + TimelineCreateUtilities.SaveAssetIntoObject(playableAsset, this); + TimelineUndo.RegisterCreatedObjectUndo(playableAsset, "Create Clip"); + + return CreateClipFromAsset(playableAsset); + } + + /// <summary> + /// Creates a timeline clip from an existing playable asset. + /// </summary> + /// <param name="asset"></param> + /// <returns></returns> + internal TimelineClip CreateClipFromPlayableAsset(IPlayableAsset asset) + { + if (asset == null) + throw new ArgumentNullException("asset"); + + if ((asset as ScriptableObject) == null) + throw new System.ArgumentException("CreateClipFromPlayableAsset " + " only supports ScriptableObject-derived Types"); + + if (!ValidateClipType(asset.GetType())) + throw new System.InvalidOperationException("Clips of type " + asset.GetType() + " are not permitted on tracks of type " + GetType()); + + return CreateClipFromAsset(asset as ScriptableObject); + } + + private TimelineClip CreateClipFromAsset(ScriptableObject playableAsset) + { + TimelineUndo.PushUndo(this, "Create Clip"); + + var newClip = CreateNewClipContainerInternal(); + newClip.displayName = playableAsset.name; + newClip.asset = playableAsset; + + IPlayableAsset iPlayableAsset = playableAsset as IPlayableAsset; + if (iPlayableAsset != null) + { + var candidateDuration = iPlayableAsset.duration; + + if (!double.IsInfinity(candidateDuration) && candidateDuration > 0) + newClip.duration = Math.Min(Math.Max(candidateDuration, TimelineClip.kMinDuration), TimelineClip.kMaxTimeValue); + } + + try + { + OnCreateClip(newClip); + } + catch (Exception e) + { + Debug.LogError(e.Message, playableAsset); + return null; + } + + return newClip; + } + + internal IEnumerable<ScriptableObject> GetMarkersRaw() + { + return m_Markers.GetRawMarkerList(); + } + + internal void ClearMarkers() + { + m_Markers.Clear(); + } + + internal void AddMarker(ScriptableObject e) + { + m_Markers.Add(e); + } + + internal bool DeleteMarkerRaw(ScriptableObject marker) + { + return m_Markers.Remove(marker, timelineAsset, this); + } + + int GetTimeRangeHash() + { + double start = double.MaxValue, end = double.MinValue; + foreach (var marker in GetMarkers()) + { + if (!(marker is INotification)) + { + continue; + } + + if (marker.time < start) + start = marker.time; + if (marker.time > end) + end = marker.time; + } + + return start.GetHashCode().CombineHash(end.GetHashCode()); + } + + internal void AddClip(TimelineClip newClip) + { + if (!m_Clips.Contains(newClip)) + { + m_Clips.Add(newClip); + m_ClipsCache = null; + } + } + + Playable CreateNotificationsPlayable(PlayableGraph graph, Playable mixerPlayable, GameObject go, Playable timelinePlayable) + { + s_BuildData.markerList.Clear(); + GatherNotificiations(s_BuildData.markerList); + var notificationPlayable = NotificationUtilities.CreateNotificationsPlayable(graph, s_BuildData.markerList, go); + if (notificationPlayable.IsValid()) + { + notificationPlayable.GetBehaviour().timeSource = timelinePlayable; + if (mixerPlayable.IsValid()) + { + notificationPlayable.SetInputCount(1); + graph.Connect(mixerPlayable, 0, notificationPlayable, 0); + notificationPlayable.SetInputWeight(mixerPlayable, 1); + } + } + + return notificationPlayable; + } + + internal Playable CreatePlayableGraph(PlayableGraph graph, GameObject go, IntervalTree<RuntimeElement> tree, Playable timelinePlayable) + { + UpdateDuration(); + var mixerPlayable = Playable.Null; + if (CanCompileClipsRecursive()) + mixerPlayable = OnCreateClipPlayableGraph(graph, go, tree); + + var notificationsPlayable = CreateNotificationsPlayable(graph, mixerPlayable, go, timelinePlayable); + if (!notificationsPlayable.IsValid() && !mixerPlayable.IsValid()) + { + Debug.LogErrorFormat("Track {0} of type {1} has no notifications and returns an invalid mixer Playable", name, + GetType().FullName); + + return Playable.Create(graph); + } + + return notificationsPlayable.IsValid() ? notificationsPlayable : mixerPlayable; + } + + internal virtual Playable CompileClips(PlayableGraph graph, GameObject go, IList<TimelineClip> timelineClips, IntervalTree<RuntimeElement> tree) + { + var blend = CreateTrackMixer(graph, go, timelineClips.Count); + for (var c = 0; c < timelineClips.Count; c++) + { + var source = CreatePlayable(graph, go, timelineClips[c]); + if (source.IsValid()) + { + source.SetDuration(timelineClips[c].duration); + var clip = new RuntimeClip(timelineClips[c], source, blend); + tree.Add(clip); + graph.Connect(source, 0, blend, c); + blend.SetInputWeight(c, 0.0f); + } + } + ConfigureTrackAnimation(tree, go, blend); + return blend; + } + + void GatherCompilableTracks(IList<TrackAsset> tracks) + { + if (!muted && CanCompileClips()) + tracks.Add(this); + + foreach (var c in GetChildTracks()) + { + if (c != null) + c.GatherCompilableTracks(tracks); + } + } + + void GatherNotificiations(List<IMarker> markers) + { + if (!muted && CanCompileNotifications()) + markers.AddRange(GetMarkers()); + foreach (var c in GetChildTracks()) + { + if (c != null) + c.GatherNotificiations(markers); + } + } + + internal virtual Playable OnCreateClipPlayableGraph(PlayableGraph graph, GameObject go, IntervalTree<RuntimeElement> tree) + { + if (tree == null) + throw new ArgumentException("IntervalTree argument cannot be null", "tree"); + + if (go == null) + throw new ArgumentException("GameObject argument cannot be null", "go"); + + s_BuildData.Clear(); + GatherCompilableTracks(s_BuildData.trackList); + + // nothing to compile + if (s_BuildData.trackList.Count == 0) + return Playable.Null; + + // check if layers are supported + Playable layerMixer = Playable.Null; + ILayerable layerable = this as ILayerable; + if (layerable != null) + layerMixer = layerable.CreateLayerMixer(graph, go, s_BuildData.trackList.Count); + + if (layerMixer.IsValid()) + { + for (int i = 0; i < s_BuildData.trackList.Count; i++) + { + var mixer = s_BuildData.trackList[i].CompileClips(graph, go, s_BuildData.trackList[i].clips, tree); + if (mixer.IsValid()) + { + graph.Connect(mixer, 0, layerMixer, i); + layerMixer.SetInputWeight(i, 1.0f); + } + } + return layerMixer; + } + + // one track compiles. Add track mixer and clips + if (s_BuildData.trackList.Count == 1) + return s_BuildData.trackList[0].CompileClips(graph, go, s_BuildData.trackList[0].clips, tree); + + // no layer mixer provided. merge down all clips. + for (int i = 0; i < s_BuildData.trackList.Count; i++) + s_BuildData.clipList.AddRange(s_BuildData.trackList[i].clips); + +#if UNITY_EDITOR + bool applyWarning = false; + for (int i = 0; i < s_BuildData.trackList.Count; i++) + applyWarning |= i > 0 && s_BuildData.trackList[i].hasCurves; + + if (applyWarning) + Debug.LogWarning("A layered track contains animated fields, but no layer mixer has been provided. Animated fields on layers will be ignored. Override CreateLayerMixer in " + s_BuildData.trackList[0].GetType().Name + " and return a valid playable to support animated fields on layered tracks."); +#endif + // compile all the clips into a single mixer + return CompileClips(graph, go, s_BuildData.clipList, tree); + } + + internal void ConfigureTrackAnimation(IntervalTree<RuntimeElement> tree, GameObject go, Playable blend) + { + if (!hasCurves) + return; + + blend.SetAnimatedProperties(m_Curves); + tree.Add(new InfiniteRuntimeClip(blend)); + + if (OnTrackAnimationPlayableCreate != null) + OnTrackAnimationPlayableCreate.Invoke(this, go, blend); + } + + // sorts clips by start time + internal void SortClips() + { + var clipsAsArray = clips; // will alloc + if (!m_CacheSorted) + { + Array.Sort(clips, (clip1, clip2) => clip1.start.CompareTo(clip2.start)); + m_CacheSorted = true; + } + } + + // clears the clips after a clone + internal void ClearClipsInternal() + { + m_Clips = new List<TimelineClip>(); + m_ClipsCache = null; + } + + internal void ClearSubTracksInternal() + { + m_Children = new List<ScriptableObject>(); + Invalidate(); + } + + // called by an owned clip when it moves + internal void OnClipMove() + { + m_CacheSorted = false; + } + + internal TimelineClip CreateNewClipContainerInternal() + { + var clipContainer = new TimelineClip(this); + clipContainer.asset = null; + + // position clip at end of sequence + var newClipStart = 0.0; + for (var a = 0; a < m_Clips.Count - 1; a++) + { + var clipDuration = m_Clips[a].duration; + if (double.IsInfinity(clipDuration)) + clipDuration = TimelineClip.kDefaultClipDurationInSeconds; + newClipStart = Math.Max(newClipStart, m_Clips[a].start + clipDuration); + } + + clipContainer.mixInCurve = AnimationCurve.EaseInOut(0, 0, 1, 1); + clipContainer.mixOutCurve = AnimationCurve.EaseInOut(0, 1, 1, 0); + clipContainer.start = newClipStart; + clipContainer.duration = TimelineClip.kDefaultClipDurationInSeconds; + clipContainer.displayName = "untitled"; + return clipContainer; + } + + internal void AddChild(TrackAsset child) + { + if (child == null) + return; + + m_Children.Add(child); + child.parent = this; + Invalidate(); + } + + internal void MoveLastTrackBefore(TrackAsset asset) + { + if (m_Children == null || m_Children.Count < 2 || asset == null) + return; + + var lastTrack = m_Children[m_Children.Count - 1]; + if (lastTrack == asset) + return; + + for (int i = 0; i < m_Children.Count - 1; i++) + { + if (m_Children[i] == asset) + { + for (int j = m_Children.Count - 1; j > i; j--) + m_Children[j] = m_Children[j - 1]; + m_Children[i] = lastTrack; + Invalidate(); + break; + } + } + } + + internal bool RemoveSubTrack(TrackAsset child) + { + if (m_Children.Remove(child)) + { + Invalidate(); + child.parent = null; + return true; + } + return false; + } + + internal void RemoveClip(TimelineClip clip) + { + m_Clips.Remove(clip); + m_ClipsCache = null; + } + + // Is this track compilable for the sequence + // calculate the time interval that this track will be evaluated in. + internal virtual void GetEvaluationTime(out double outStart, out double outDuration) + { + outStart = double.PositiveInfinity; + var outEnd = double.NegativeInfinity; + + if (hasCurves) + { + outStart = 0.0; + outEnd = TimeUtility.GetAnimationClipLength(curves); + } + + foreach (var clip in clips) + { + outStart = Math.Min(clip.start, outStart); + outEnd = Math.Max(clip.end, outEnd); + } + + if (HasNotifications()) + { + var notificationDuration = GetNotificationDuration(); + outStart = Math.Min(notificationDuration, outStart); + outEnd = Math.Max(notificationDuration, outEnd); + } + + if (double.IsInfinity(outStart) || double.IsInfinity(outEnd)) + outStart = outDuration = 0.0; + else + outDuration = outEnd - outStart; + } + + // calculate the time interval that the sequence will use to determine length. + // by default this is the same as the evaluation, but subclasses can have different + // behaviour + internal virtual void GetSequenceTime(out double outStart, out double outDuration) + { + GetEvaluationTime(out outStart, out outDuration); + } + + /// <summary> + /// Called by the Timeline Editor to gather properties requiring preview. + /// </summary> + /// <param name="director">The PlayableDirector invoking the preview</param> + /// <param name="driver">PropertyCollector used to gather previewable properties</param> + public virtual void GatherProperties(PlayableDirector director, IPropertyCollector driver) + { + // only push on game objects if there is a binding. Subtracks + // will use objects on the stack + var gameObject = GetGameObjectBinding(director); + if (gameObject != null) + driver.PushActiveGameObject(gameObject); + + if (hasCurves) + driver.AddObjectProperties(this, m_Curves); + + foreach (var clip in clips) + { + if (clip.curves != null && clip.asset != null) + driver.AddObjectProperties(clip.asset, clip.curves); + + IPropertyPreview modifier = clip.asset as IPropertyPreview; + if (modifier != null) + modifier.GatherProperties(director, driver); + } + + foreach (var subtrack in GetChildTracks()) + { + if (subtrack != null) + subtrack.GatherProperties(director, driver); + } + + if (gameObject != null) + driver.PopActiveGameObject(); + } + + internal GameObject GetGameObjectBinding(PlayableDirector director) + { + if (director == null) + return null; + + var binding = director.GetGenericBinding(this); + + var gameObject = binding as GameObject; + if (gameObject != null) + return gameObject; + + var comp = binding as Component; + if (comp != null) + return comp.gameObject; + + return null; + } + + internal bool ValidateClipType(Type clipType) + { + var attrs = GetType().GetCustomAttributes(typeof(TrackClipTypeAttribute), true); + for (var c = 0; c < attrs.Length; ++c) + { + var attr = (TrackClipTypeAttribute)attrs[c]; + if (attr.inspectedType.IsAssignableFrom(clipType)) + return true; + } + + // special case for playable tracks, they accept all clips (in the runtime) + return typeof(PlayableTrack).IsAssignableFrom(GetType()) && + typeof(IPlayableAsset).IsAssignableFrom(clipType) && + typeof(ScriptableObject).IsAssignableFrom(clipType); + } + + /// <summary> + /// Called when a clip is created on a track. + /// </summary> + /// <param name="clip">The timeline clip added to this track</param> + /// <remarks>Use this method to set default values on a timeline clip, or it's PlayableAsset.</remarks> + protected virtual void OnCreateClip(TimelineClip clip) {} + + void UpdateDuration() + { + // check if something changed in the clips that require a re-calculation of the evaluation times. + var itemsHash = CalculateItemsHash(); + if (itemsHash == m_ItemsHash) + return; + m_ItemsHash = itemsHash; + + double trackStart, trackDuration; + GetSequenceTime(out trackStart, out trackDuration); + + m_Start = (DiscreteTime)trackStart; + m_End = (DiscreteTime)(trackStart + trackDuration); + + // calculate the extrapolations time. + // TODO Extrapolation time should probably be extracted from the SequenceClip so only a track is aware of it. + this.CalculateExtrapolationTimes(); + } + + protected internal virtual int CalculateItemsHash() + { + return HashUtility.CombineHash(GetClipsHash(), GetAnimationClipHash(m_Curves), GetTimeRangeHash()); + } + + /// <summary> + /// Constructs a Playable from a TimelineClip. + /// </summary> + /// <param name="graph">PlayableGraph that will own the playable.</param> + /// <param name="gameObject">The GameObject that builds the PlayableGraph.</param> + /// <param name="clip">The TimelineClip to construct a playable for.</param> + /// <returns>A playable that will be set as an input to the Track Mixer playable, or Playable.Null if the clip does not have a valid PlayableAsset</returns> + /// <exception cref="ArgumentException">Thrown if the specified PlayableGraph is not valid.</exception> + /// <exception cref="ArgumentNullException">Thrown if the specified TimelineClip is not valid.</exception> + /// <remarks> + /// By default, this method invokes Playable.CreatePlayable, sets animated properties, and sets the speed of the created playable. Override this method to change this default implementation. + /// </remarks> + protected virtual Playable CreatePlayable(PlayableGraph graph, GameObject gameObject, TimelineClip clip) + { + if (!graph.IsValid()) + throw new ArgumentException("graph must be a valid PlayableGraph"); + if (clip == null) + throw new ArgumentNullException("clip"); + + var asset = clip.asset as IPlayableAsset; + if (asset != null) + { + var handle = asset.CreatePlayable(graph, gameObject); + if (handle.IsValid()) + { + handle.SetAnimatedProperties(clip.curves); + handle.SetSpeed(clip.timeScale); + if (OnClipPlayableCreate != null) + OnClipPlayableCreate(clip, gameObject, handle); + } + return handle; + } + return Playable.Null; + } + + internal void Invalidate() + { + m_ChildTrackCache = null; + var timeline = timelineAsset; + if (timeline != null) + { + timeline.Invalidate(); + } + } + + internal double GetNotificationDuration() + { + if (!supportsNotifications) + { + return 0; + } + + var maxTime = 0.0; + foreach (var marker in GetMarkers()) + { + if (!(marker is INotification)) + { + continue; + } + maxTime = Math.Max(maxTime, marker.time); + } + + return maxTime; + } + + internal virtual bool CanCompileClips() + { + return hasClips || hasCurves; + } + + internal bool IsCompilable() + { + var isContainer = typeof(GroupTrack).IsAssignableFrom(GetType()); + + if (isContainer) + return false; + + var ret = !mutedInHierarchy && (CanCompileClips() || CanCompileNotifications()); + if (!ret) + { + foreach (var t in GetChildTracks()) + { + if (t.IsCompilable()) + return true; + } + } + + return ret; + } + + private void UpdateChildTrackCache() + { + if (m_ChildTrackCache == null) + { + if (m_Children == null || m_Children.Count == 0) + m_ChildTrackCache = s_EmptyCache; + else + { + var childTracks = new List<TrackAsset>(m_Children.Count); + for (int i = 0; i < m_Children.Count; i++) + { + var subTrack = m_Children[i] as TrackAsset; + if (subTrack != null) + childTracks.Add(subTrack); + } + m_ChildTrackCache = childTracks; + } + } + } + + internal virtual int Hash() + { + return clips.Length + (m_Markers.Count << 16); + } + + int GetClipsHash() + { + var hash = 0; + foreach (var clip in m_Clips) + { + hash = hash.CombineHash(clip.Hash()); + } + return hash; + } + + protected static int GetAnimationClipHash(AnimationClip clip) + { + var hash = 0; + if (clip != null && !clip.empty) + hash = hash.CombineHash(clip.frameRate.GetHashCode()) + .CombineHash(clip.length.GetHashCode()); + + return hash; + } + + bool HasNotifications() + { + return m_Markers.HasNotifications(); + } + + bool CanCompileNotifications() + { + return supportsNotifications && m_Markers.HasNotifications(); + } + + bool CanCompileClipsRecursive() + { + if (CanCompileClips()) + return true; + foreach (var track in GetChildTracks()) + { + if (track.CanCompileClipsRecursive()) + return true; + } + + return false; + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TrackAsset.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TrackAsset.cs.meta new file mode 100644 index 0000000..06213be --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/TrackAsset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3ad53269c7421084ab67f804591994e0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Unity.Timeline.asmdef b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Unity.Timeline.asmdef new file mode 100644 index 0000000..d4d4bbe --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Unity.Timeline.asmdef @@ -0,0 +1,6 @@ +{ + "name": "Unity.Timeline", + "references": [], + "includePlatforms": [], + "excludePlatforms": [] +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Unity.Timeline.asmdef.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Unity.Timeline.asmdef.meta new file mode 100644 index 0000000..454c5db --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Unity.Timeline.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f06555f75b070af458a003d92f9efb00 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities.meta new file mode 100644 index 0000000..b9c8db0 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f8730045d7da0f84cb11c0d868899577 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/AnimationPreviewUtilities.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/AnimationPreviewUtilities.cs new file mode 100644 index 0000000..b8ab669 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/AnimationPreviewUtilities.cs @@ -0,0 +1,266 @@ +#if UNITY_EDITOR +using System.Collections.Generic; +using UnityEditor; + + +namespace UnityEngine.Timeline +{ + static class AnimationPreviewUtilities + { + private const string k_PosX = "m_LocalPosition.x"; + private const string k_PosY = "m_LocalPosition.y"; + private const string k_PosZ = "m_LocalPosition.z"; + private const string k_RotX = "m_LocalRotation.x"; + private const string k_RotY = "m_LocalRotation.y"; + private const string k_RotZ = "m_LocalRotation.z"; + private const string k_RotW = "m_LocalRotation.w"; + private const string k_ScaleX = "m_LocalScale.x"; + private const string k_ScaleY = "m_LocalScale.y"; + private const string k_ScaleZ = "m_LocalScale.z"; + private const string k_EulerAnglesRaw = "localEulerAnglesRaw"; + private const string k_EulerHint = "m_LocalEulerAnglesHint"; + private const string k_Pos = "m_LocalPosition"; + private const string k_Rot = "m_LocalRotation"; + private const string k_MotionT = "MotionT"; + private const string k_MotionQ = "MotionQ"; + private const string k_RootT = "RootT"; + private const string k_RootQ = "RootQ"; + + + internal class EditorCurveBindingComparer : IEqualityComparer<EditorCurveBinding> + { + public bool Equals(EditorCurveBinding x, EditorCurveBinding y) { return x.path.Equals(y.path) && x.type == y.type && x.propertyName == y.propertyName; } + public int GetHashCode(EditorCurveBinding obj) + { + return obj.propertyName.GetHashCode() ^ obj.path.GetHashCode(); + } + + public static readonly EditorCurveBindingComparer Instance = new EditorCurveBindingComparer(); + } + + // a dictionary is faster than a hashset, because the capacity can be pre-set + private static readonly Dictionary<EditorCurveBinding, int> s_CurveSet = new Dictionary<EditorCurveBinding, int>(10000, EditorCurveBindingComparer.Instance); + private static readonly AnimatorBindingCache s_BindingCache = new AnimatorBindingCache(); + + public static void ClearCaches() + { + s_BindingCache.Clear(); + s_CurveSet.Clear(); + } + + public static EditorCurveBinding[] GetBindings(GameObject animatorRoot, IEnumerable<AnimationClip> clips) + { + s_CurveSet.Clear(); + foreach (var clip in clips) + { + AddBindings(s_BindingCache.GetCurveBindings(clip)); + } + + // if we have a transform binding, bind the entire skeleton + if (NeedsSkeletonBindings(s_CurveSet.Keys)) + AddBindings(s_BindingCache.GetAnimatorBindings(animatorRoot)); + + var bindings = new EditorCurveBinding[s_CurveSet.Keys.Count]; + s_CurveSet.Keys.CopyTo(bindings, 0); + return bindings; + } + + public static void PreviewFromCurves(GameObject animatorRoot, IEnumerable<EditorCurveBinding> keys) + { + if (!AnimationMode.InAnimationMode()) + return; + + var avatarRoot = GetAvatarRoot(animatorRoot); + foreach (var binding in keys) + { + if (IsAvatarBinding(binding) || IsEuler(binding)) + continue; + + bool isTransform = typeof(Transform).IsAssignableFrom(binding.type); + if (isTransform && binding.propertyName == AnimatorBindingCache.TRPlaceHolder) + AddTRBinding(animatorRoot, binding); + else if (isTransform && binding.propertyName == AnimatorBindingCache.ScalePlaceholder) + AddScaleBinding(animatorRoot, binding); + else + AnimationMode.AddEditorCurveBinding(avatarRoot, binding); + } + } + + public static AnimationClip CreateDefaultClip(GameObject animatorRoot, IEnumerable<EditorCurveBinding> keys) + { + AnimationClip animClip = new AnimationClip() { name = "DefaultPose" }; + var keyFrames = new[] {new Keyframe(0, 0)}; + var curve = new AnimationCurve(keyFrames); + bool rootMotion = false; + var avatarRoot = GetAvatarRoot(animatorRoot); + + foreach (var binding in keys) + { + if (IsRootMotion(binding)) + { + rootMotion = true; + continue; + } + + if (typeof(Transform).IsAssignableFrom(binding.type) && binding.propertyName == AnimatorBindingCache.TRPlaceHolder) + { + if (string.IsNullOrEmpty(binding.path)) + rootMotion = true; + else + { + var transform = animatorRoot.transform.Find(binding.path); + if (transform != null) + { + var pos = transform.localPosition; + var rot = transform.localRotation; + animClip.SetCurve(binding.path, typeof(Transform), k_PosX, SetZeroKey(curve, keyFrames, pos.x)); + animClip.SetCurve(binding.path, typeof(Transform), k_PosY, SetZeroKey(curve, keyFrames, pos.y)); + animClip.SetCurve(binding.path, typeof(Transform), k_PosZ, SetZeroKey(curve, keyFrames, pos.z)); + animClip.SetCurve(binding.path, typeof(Transform), k_RotX, SetZeroKey(curve, keyFrames, rot.x)); + animClip.SetCurve(binding.path, typeof(Transform), k_RotY, SetZeroKey(curve, keyFrames, rot.y)); + animClip.SetCurve(binding.path, typeof(Transform), k_RotZ, SetZeroKey(curve, keyFrames, rot.z)); + animClip.SetCurve(binding.path, typeof(Transform), k_RotW, SetZeroKey(curve, keyFrames, rot.w)); + } + } + + continue; + } + + if (typeof(Transform).IsAssignableFrom(binding.type) && binding.propertyName == AnimatorBindingCache.ScalePlaceholder) + { + var transform = animatorRoot.transform.Find(binding.path); + if (transform != null) + { + var scale = transform.localScale; + animClip.SetCurve(binding.path, typeof(Transform), k_ScaleX, SetZeroKey(curve, keyFrames, scale.x)); + animClip.SetCurve(binding.path, typeof(Transform), k_ScaleY, SetZeroKey(curve, keyFrames, scale.y)); + animClip.SetCurve(binding.path, typeof(Transform), k_ScaleZ, SetZeroKey(curve, keyFrames, scale.z)); + } + + continue; + } + + // Not setting curves through AnimationUtility.SetEditorCurve to avoid reentrant + // onCurveWasModified calls in timeline. This means we don't get sprite curves + // in the default clip right now. + if (IsAvatarBinding(binding) || IsEulerHint(binding) || binding.isPPtrCurve) + continue; + + float floatValue; + AnimationUtility.GetFloatValue(avatarRoot, binding, out floatValue); + animClip.SetCurve(binding.path, binding.type, binding.propertyName, SetZeroKey(curve, keyFrames, floatValue)); + } + + // add root motion explicitly. + if (rootMotion) + { + var pos = Vector3.zero; // the appropriate root motion offsets are applied by timeline + var rot = Quaternion.identity; + animClip.SetCurve(string.Empty, typeof(Transform), k_PosX, SetZeroKey(curve, keyFrames, pos.x)); + animClip.SetCurve(string.Empty, typeof(Transform), k_PosY, SetZeroKey(curve, keyFrames, pos.y)); + animClip.SetCurve(string.Empty, typeof(Transform), k_PosZ, SetZeroKey(curve, keyFrames, pos.z)); + animClip.SetCurve(string.Empty, typeof(Transform), k_RotX, SetZeroKey(curve, keyFrames, rot.x)); + animClip.SetCurve(string.Empty, typeof(Transform), k_RotY, SetZeroKey(curve, keyFrames, rot.y)); + animClip.SetCurve(string.Empty, typeof(Transform), k_RotZ, SetZeroKey(curve, keyFrames, rot.z)); + animClip.SetCurve(string.Empty, typeof(Transform), k_RotW, SetZeroKey(curve, keyFrames, rot.w)); + } + + return animClip; + } + + public static bool IsRootMotion(EditorCurveBinding binding) + { + // Root Transform TR. + if (typeof(Transform).IsAssignableFrom(binding.type) && string.IsNullOrEmpty(binding.path)) + { + return binding.propertyName.StartsWith(k_Pos) || binding.propertyName.StartsWith(k_Rot); + } + + // MotionCurves/RootCurves. + if (binding.type == typeof(Animator)) + { + return binding.propertyName.StartsWith(k_MotionT) || binding.propertyName.StartsWith(k_MotionQ) || + binding.propertyName.StartsWith(k_RootT) || binding.propertyName.StartsWith(k_RootQ); + } + + return false; + } + + private static bool NeedsSkeletonBindings(IEnumerable<EditorCurveBinding> bindings) + { + foreach (var b in bindings) + { + if (IsSkeletalBinding(b)) + return true; + } + + return false; + } + + private static void AddBindings(IEnumerable<EditorCurveBinding> bindings) + { + foreach (var b in bindings) + { + if (!s_CurveSet.ContainsKey(b)) + s_CurveSet[b] = 1; + } + } + + private static void AddTRBinding(GameObject root, EditorCurveBinding binding) + { + // This is faster than AnimationMode.AddTransformTR + binding.propertyName = k_PosX; AnimationMode.AddEditorCurveBinding(root, binding); + binding.propertyName = k_PosY; AnimationMode.AddEditorCurveBinding(root, binding); + binding.propertyName = k_PosZ; AnimationMode.AddEditorCurveBinding(root, binding); + binding.propertyName = k_RotX; AnimationMode.AddEditorCurveBinding(root, binding); + binding.propertyName = k_RotY; AnimationMode.AddEditorCurveBinding(root, binding); + binding.propertyName = k_RotZ; AnimationMode.AddEditorCurveBinding(root, binding); + binding.propertyName = k_RotW; AnimationMode.AddEditorCurveBinding(root, binding); + } + + private static void AddScaleBinding(GameObject root, EditorCurveBinding binding) + { + // AnimationMode.AddTransformTRS is slow + binding.propertyName = k_ScaleX; AnimationMode.AddEditorCurveBinding(root, binding); + binding.propertyName = k_ScaleY; AnimationMode.AddEditorCurveBinding(root, binding); + binding.propertyName = k_ScaleZ; AnimationMode.AddEditorCurveBinding(root, binding); + } + + private static bool IsEuler(EditorCurveBinding binding) + { + return typeof(Transform).IsAssignableFrom(binding.type) && binding.propertyName.StartsWith(k_EulerAnglesRaw); + } + + private static bool IsAvatarBinding(EditorCurveBinding binding) + { + return typeof(Animator).IsAssignableFrom(binding.type) && string.IsNullOrEmpty(binding.path); + } + + private static bool IsSkeletalBinding(EditorCurveBinding binding) + { + // skin mesh incorporates blend shapes + return typeof(Transform).IsAssignableFrom(binding.type) || typeof(SkinnedMeshRenderer).IsAssignableFrom(binding.type); + } + + private static AnimationCurve SetZeroKey(AnimationCurve curve, Keyframe[] keys, float val) + { + keys[0].value = val; + curve.keys = keys; + return curve; + } + + private static bool IsEulerHint(EditorCurveBinding binding) + { + return typeof(Transform).IsAssignableFrom(binding.type) && binding.propertyName.StartsWith(k_EulerHint); + } + + private static GameObject GetAvatarRoot(GameObject animatorRoot) + { + var animator = animatorRoot.GetComponent<Animator>(); + if (animator != null && animator.avatarRoot != animatorRoot.transform) + return animator.avatarRoot.gameObject; + return animatorRoot; + } + } +} +#endif diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/AnimationPreviewUtilities.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/AnimationPreviewUtilities.cs.meta new file mode 100644 index 0000000..82e3768 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/AnimationPreviewUtilities.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 01da6c5b7c781174d818662ce6f39b8b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/AnimatorBindingCache.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/AnimatorBindingCache.cs new file mode 100644 index 0000000..53198ea --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/AnimatorBindingCache.cs @@ -0,0 +1,133 @@ +#if UNITY_EDITOR +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Playables; +using UnityEngine.Timeline; +using UnityEditor; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// Animator to Editor Curve Binding cache. Used to prevent frequent calls to GetAnimatorBindings which can be costly + /// </summary> + class AnimatorBindingCache + { + public const string TRPlaceHolder = "TransformTR"; + public const string ScalePlaceholder = "TransformScale"; + + struct AnimatorEntry + { + public int animatorID; + public bool applyRootMotion; + public bool humanoid; + } + + class AnimatorEntryComparer : IEqualityComparer<AnimatorEntry> + { + public bool Equals(AnimatorEntry x, AnimatorEntry y) { return x.animatorID == y.animatorID && x.applyRootMotion == y.applyRootMotion && x.humanoid == y.humanoid; } + public int GetHashCode(AnimatorEntry obj) { return HashUtility.CombineHash(obj.animatorID, obj.applyRootMotion.GetHashCode(), obj.humanoid.GetHashCode()); } + public static readonly AnimatorEntryComparer Instance = new AnimatorEntryComparer(); + } + + readonly Dictionary<AnimatorEntry, EditorCurveBinding[]> m_AnimatorCache = new Dictionary<AnimatorEntry, EditorCurveBinding[]>(AnimatorEntryComparer.Instance); + readonly Dictionary<AnimationClip, EditorCurveBinding[]> m_ClipCache = new Dictionary<AnimationClip, EditorCurveBinding[]>(); + + private static readonly EditorCurveBinding[] kEmptyArray = new EditorCurveBinding[0]; + private static readonly List<EditorCurveBinding> s_BindingScratchPad = new List<EditorCurveBinding>(1000); + + public AnimatorBindingCache() + { + AnimationUtility.onCurveWasModified += OnCurveWasModified; + } + + public EditorCurveBinding[] GetAnimatorBindings(GameObject gameObject) + { + if (gameObject == null) + return kEmptyArray; + + Animator animator = gameObject.GetComponent<Animator>(); + if (animator == null) + return kEmptyArray; + + AnimatorEntry entry = new AnimatorEntry() + { + animatorID = animator.GetInstanceID(), + applyRootMotion = animator.applyRootMotion, + humanoid = animator.isHuman + }; + + EditorCurveBinding[] result = null; + if (m_AnimatorCache.TryGetValue(entry, out result)) + return result; + + s_BindingScratchPad.Clear(); + + // Replacement for AnimationMode.GetAnimatorBinding - this is faster and allocates kB instead of MB + var transforms = animator.GetComponentsInChildren<Transform>(); + foreach (var t in transforms) + { + if (animator.IsBoneTransform(t)) + s_BindingScratchPad.Add(EditorCurveBinding.FloatCurve(AnimationUtility.CalculateTransformPath(t, animator.transform), typeof(Transform), TRPlaceHolder)); + } + + var streamBindings = AnimationUtility.GetAnimationStreamBindings(animator.gameObject); + UpdateTransformBindings(streamBindings); + s_BindingScratchPad.AddRange(streamBindings); + + result = new EditorCurveBinding[s_BindingScratchPad.Count]; + s_BindingScratchPad.CopyTo(result); + m_AnimatorCache[entry] = result; + return result; + } + + public EditorCurveBinding[] GetCurveBindings(AnimationClip clip) + { + if (clip == null) + return kEmptyArray; + + EditorCurveBinding[] result; + if (!m_ClipCache.TryGetValue(clip, out result)) + { + result = AnimationMode.GetCurveBindings(clip); + UpdateTransformBindings(result); + m_ClipCache[clip] = result; + } + + return result; + } + + private static void UpdateTransformBindings(EditorCurveBinding[] bindings) + { + for (int i = 0; i < bindings.Length; i++) + { + var binding = bindings[i]; + if (AnimationPreviewUtilities.IsRootMotion(binding)) + { + binding.type = typeof(Transform); + binding.propertyName = TRPlaceHolder; + } + else if (typeof(Transform).IsAssignableFrom(binding.type) && (binding.propertyName.StartsWith("m_LocalRotation.") || binding.propertyName.StartsWith("m_LocalPosition."))) + { + binding.propertyName = TRPlaceHolder; + } + else if (typeof(Transform).IsAssignableFrom(binding.type) && binding.propertyName.StartsWith("m_LocalScale.")) + { + binding.propertyName = ScalePlaceholder; + } + bindings[i] = binding; + } + } + + public void Clear() + { + m_AnimatorCache.Clear(); + m_ClipCache.Clear(); + } + + void OnCurveWasModified(AnimationClip clip, EditorCurveBinding binding, AnimationUtility.CurveModifiedType modification) + { + m_ClipCache.Remove(clip); + } + } +} +#endif diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/AnimatorBindingCache.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/AnimatorBindingCache.cs.meta new file mode 100644 index 0000000..dc6dc1d --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/AnimatorBindingCache.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d0080567f62c3f94cb75b2927a349e22 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/Extrapolation.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/Extrapolation.cs new file mode 100644 index 0000000..34408c9 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/Extrapolation.cs @@ -0,0 +1,92 @@ +using System; +using UnityEngine; + +// Extension methods responsible for managing extrapolation time +namespace UnityEngine.Timeline +{ + static class Extrapolation + { + /// <summary> + /// The minimum amount of extrapolation time to apply + /// </summary> + internal static readonly double kMinExtrapolationTime = TimeUtility.kTimeEpsilon * 1000; + + // Calculates the extrapolation times + internal static void CalculateExtrapolationTimes(this TrackAsset asset) + { + TimelineClip[] clips = asset.clips; + if (clips == null || clips.Length == 0) + return; + + // extrapolation not supported + if (!clips[0].SupportsExtrapolation()) + return; + + var orderedClips = SortClipsByStartTime(clips); + if (orderedClips.Length > 0) + { + // post extrapolation is the minimum time to the next clip + for (int i = 0; i < orderedClips.Length; i++) + { + double minTime = double.PositiveInfinity; + for (int j = 0; j < orderedClips.Length; j++) + { + if (i == j) + continue; + + double deltaTime = orderedClips[j].start - orderedClips[i].end; + if (deltaTime >= -TimeUtility.kTimeEpsilon && deltaTime < minTime) + minTime = Math.Min(minTime, deltaTime); + // check for overlapped clips + if (orderedClips[j].start <= orderedClips[i].end && orderedClips[j].end > orderedClips[i].end) + minTime = 0; + } + minTime = minTime <= kMinExtrapolationTime ? 0 : minTime; + orderedClips[i].SetPostExtrapolationTime(minTime); + } + + // the first clip gets pre-extrapolation, then it's only respected if there is no post extrapolation + orderedClips[0].SetPreExtrapolationTime(Math.Max(0, orderedClips[0].start)); + for (int i = 1; i < orderedClips.Length; i++) + { + double preTime = 0; + int prevClip = -1; + for (int j = 0; j < i; j++) + { + // overlap, no pre-time + if (orderedClips[j].end > orderedClips[i].start) + { + prevClip = -1; + preTime = 0; + break; + } + + double gap = orderedClips[i].start - orderedClips[j].end; + if (prevClip == -1 || gap < preTime) + { + preTime = gap; + prevClip = j; + } + } + // check for a post extrapolation time + if (prevClip >= 0) + { + if (orderedClips[prevClip].postExtrapolationMode != TimelineClip.ClipExtrapolation.None) + preTime = 0; + } + + preTime = preTime <= kMinExtrapolationTime ? 0 : preTime; + orderedClips[i].SetPreExtrapolationTime(preTime); + } + } + } + + static TimelineClip[] SortClipsByStartTime(TimelineClip[] clips) + { + var orderedClips = new TimelineClip[clips.Length]; + Array.Copy(clips, orderedClips, clips.Length); + Array.Sort(orderedClips, (clip1, clip2) => clip1.start.CompareTo(clip2.start)); + return orderedClips; + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/Extrapolation.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/Extrapolation.cs.meta new file mode 100644 index 0000000..69c90cf --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/Extrapolation.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 32535dd294c621e4297fba34b15b1c52 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/HashUtility.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/HashUtility.cs new file mode 100644 index 0000000..81fa940 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/HashUtility.cs @@ -0,0 +1,51 @@ +namespace UnityEngine.Timeline +{ + static class HashUtility + { + // Note. We could have used "params int[] hashes" but we want to avoid allocating. + + public static int CombineHash(this int h1, int h2) + { + return h1 ^ (int)(h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2)); // Similar to c++ boost::hash_combine + } + + public static int CombineHash(int h1, int h2, int h3) + { + return CombineHash(h1, h2).CombineHash(h3); + } + + public static int CombineHash(int h1, int h2, int h3, int h4) + { + return CombineHash(h1, h2, h3).CombineHash(h4); + } + + public static int CombineHash(int h1, int h2, int h3, int h4, int h5) + { + return CombineHash(h1, h2, h3, h4).CombineHash(h5); + } + + public static int CombineHash(int h1, int h2, int h3, int h4, int h5, int h6) + { + return CombineHash(h1, h2, h3, h4, h5).CombineHash(h6); + } + + public static int CombineHash(int h1, int h2, int h3, int h4, int h5, int h6, int h7) + { + return CombineHash(h1, h2, h3, h4, h5, h6).CombineHash(h7); + } + + public static int CombineHash(int[] hashes) + { + if (hashes == null || hashes.Length == 0) + return 0; + + var h = hashes[0]; + for (int i = 1; i < hashes.Length; ++i) + { + h = CombineHash(h, hashes[i]); + } + + return h; + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/HashUtility.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/HashUtility.cs.meta new file mode 100644 index 0000000..fec5c19 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/HashUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d0ca7b2e84542bf4ab9987087e8d79ad +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/IPropertyCollector.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/IPropertyCollector.cs new file mode 100644 index 0000000..08f991a --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/IPropertyCollector.cs @@ -0,0 +1,102 @@ +using System.Collections.Generic; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// Interface used to inform the Timeline Editor about potential property modifications that may occur while previewing. + /// </summary> + public interface IPropertyCollector + { + /// <summary> + /// Sets the active game object for subsequent property modifications. + /// </summary> + /// <param name="gameObject">The GameObject to push.</param> + void PushActiveGameObject(GameObject gameObject); + + /// <summary> + /// Removes the active GameObject from the modification stack, restoring the previous value. + /// </summary> + void PopActiveGameObject(); + + /// <summary> + /// Add properties modified by an animation clip. + /// </summary> + /// <param name="clip">The animation clip that contains the properties</param> + void AddFromClip(AnimationClip clip); + + /// <summary> + /// Add property modifications specified by a list of animation clips. + /// </summary> + /// <param name="clips">The list of animation clips used to determine which property modifications to apply.</param> + void AddFromClips(IEnumerable<AnimationClip> clips); + + /// <summary> + /// Add property modifications using the serialized property name. + /// </summary> + /// <param name="name">The name of the serialized property</param> + /// <typeparam name="T">The type of the component the property exists on</typeparam> + /// <remarks> + /// This method uses the most recent gameObject from PushActiveGameObject + /// </remarks> + void AddFromName<T>(string name) where T : Component; + + /// <summary> + /// Add property modifications using the serialized property name. + /// </summary> + /// <param name="name">The name of the serialized property</param> + /// <remarks> + /// This method uses the most recent gameObject from PushActiveGameObject + /// </remarks> + void AddFromName(string name); + + /// <summary> + /// Add property modifications modified by an animation clip. + /// </summary> + /// <param name="obj">The GameObject where the properties exist</param> + /// <param name="clip">The animation clip that contains the properties</param> + void AddFromClip(GameObject obj, AnimationClip clip); + + /// <summary> + /// Add property modifications specified by a list of animation clips. + /// </summary> + /// <param name="obj">The gameObject that will be animated</param> + /// <param name="clips">The list of animation clips used to determine which property modifications to apply.</param> + void AddFromClips(GameObject obj, IEnumerable<AnimationClip> clips); + + /// <summary> + /// Add property modifications using the serialized property name. + /// </summary> + /// <param name="name">The name of the serialized property</param> + /// <param name="obj">The gameObject where the properties exist</param> + /// <typeparam name="T">The type of the component the property exists on</typeparam>> + void AddFromName<T>(GameObject obj, string name) where T : Component; + + /// <summary> + /// Add property modifications using the serialized property name. + /// </summary> + /// <param name="obj">The gameObject where the properties exist</param> + /// <param name="name">The name of the serialized property</param> + void AddFromName(GameObject obj, string name); + + /// <summary> + /// Add property modifications using the serialized property name. + /// </summary> + /// <param name="name">The name of the serialized property</param> + /// <param name="component">The component where the properties exist</param> + void AddFromName(Component component, string name); + + /// <summary> + /// Set all serializable properties on a component to be under preview control. + /// </summary> + /// <param name="obj">The gameObject where the properties exist</param> + /// <param name="component">The component to set in preview mode</param> + void AddFromComponent(GameObject obj, Component component); + + /// <summary> + /// Add property modifications modified by an animation clip. + /// </summary> + /// <param name="obj">The Object where the properties exist</param> + /// <param name="clip">The animation clip that contains the properties</param> + void AddObjectProperties(Object obj, AnimationClip clip); + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/IPropertyCollector.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/IPropertyCollector.cs.meta new file mode 100644 index 0000000..05ecf1d --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/IPropertyCollector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 66b2b8fd1d9b4bc4c96b07335ad822f3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/IPropertyPreview.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/IPropertyPreview.cs new file mode 100644 index 0000000..b779f15 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/IPropertyPreview.cs @@ -0,0 +1,17 @@ +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + /// <summary> + /// Implement this interface in a PlayableAsset to specify which properties will be modified when Timeline is in preview mode. + /// </summary> + public interface IPropertyPreview + { + /// <summary> + /// Called by the Timeline Editor to gather properties requiring preview. + /// </summary> + /// <param name="director">The PlayableDirector invoking the preview</param> + /// <param name="driver">PropertyCollector used to gather previewable properties</param> + void GatherProperties(PlayableDirector director, IPropertyCollector driver); + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/IPropertyPreview.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/IPropertyPreview.cs.meta new file mode 100644 index 0000000..31806d8 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/IPropertyPreview.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b5f0881228e5827438f74e9b7b33c2dc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/NotificationUtilities.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/NotificationUtilities.cs new file mode 100644 index 0000000..41aabce --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/NotificationUtilities.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + static class NotificationUtilities + { + public static ScriptPlayable<TimeNotificationBehaviour> CreateNotificationsPlayable(PlayableGraph graph, IEnumerable<IMarker> markers, GameObject go) + { + var notificationPlayable = ScriptPlayable<TimeNotificationBehaviour>.Null; + var director = go.GetComponent<PlayableDirector>(); + foreach (var e in markers) + { + var notif = e as INotification; + if (notif == null) + continue; + + if (notificationPlayable.Equals(ScriptPlayable<TimeNotificationBehaviour>.Null)) + { + notificationPlayable = TimeNotificationBehaviour.Create(graph, + director.playableAsset.duration, director.extrapolationMode); + } + + var time = (DiscreteTime)e.time; + var tlDuration = (DiscreteTime)director.playableAsset.duration; + if (time >= tlDuration && time <= tlDuration.OneTickAfter() && tlDuration != 0) + { + time = tlDuration.OneTickBefore(); + } + + var notificationOptionProvider = e as INotificationOptionProvider; + if (notificationOptionProvider != null) + { + notificationPlayable.GetBehaviour().AddNotification((double)time, notif, notificationOptionProvider.flags); + } + else + { + notificationPlayable.GetBehaviour().AddNotification((double)time, notif); + } + } + + return notificationPlayable; + } + + public static bool TrackTypeSupportsNotifications(Type type) + { + var binding = (TrackBindingTypeAttribute)Attribute.GetCustomAttribute(type, typeof(TrackBindingTypeAttribute)); + return binding != null && + (typeof(Component).IsAssignableFrom(binding.type) || + typeof(GameObject).IsAssignableFrom(binding.type)); + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/NotificationUtilities.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/NotificationUtilities.cs.meta new file mode 100644 index 0000000..6e5c8c3 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/NotificationUtilities.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b90311a8f07b00f4bbeb2fff3b128d25 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/TimeUtility.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/TimeUtility.cs new file mode 100644 index 0000000..549de4c --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/TimeUtility.cs @@ -0,0 +1,212 @@ +using System; +using System.Text.RegularExpressions; + +namespace UnityEngine.Timeline +{ + // Sequence specific utilities for time manipulation + static class TimeUtility + { + // chosen because it will cause no rounding errors between time/frames for frames values up to at least 10 million + public static readonly double kTimeEpsilon = 1e-14; + public static readonly double kFrameRateEpsilon = 1e-6; + public static readonly double k_MaxTimelineDurationInSeconds = 9e6; //104 days of running time + + static void ValidateFrameRate(double frameRate) + { + if (frameRate <= kTimeEpsilon) + throw new ArgumentException("frame rate cannot be 0 or negative"); + } + + public static int ToFrames(double time, double frameRate) + { + ValidateFrameRate(frameRate); + time = Math.Min(Math.Max(time, -k_MaxTimelineDurationInSeconds), k_MaxTimelineDurationInSeconds); + // this matches OnFrameBoundary + double tolerance = GetEpsilon(time, frameRate) / 2.0; + if (time < 0) + { + return (int)Math.Ceiling(time * frameRate - tolerance); + } + return (int)Math.Floor(time * frameRate + tolerance); + } + + public static double ToExactFrames(double time, double frameRate) + { + ValidateFrameRate(frameRate); + return time * frameRate; + } + + public static double FromFrames(int frames, double frameRate) + { + ValidateFrameRate(frameRate); + return (frames / frameRate); + } + + public static double FromFrames(double frames, double frameRate) + { + ValidateFrameRate(frameRate); + return frames / frameRate; + } + + public static bool OnFrameBoundary(double time, double frameRate) + { + return OnFrameBoundary(time, frameRate, GetEpsilon(time, frameRate)); + } + + public static double GetEpsilon(double time, double frameRate) + { + return Math.Max(Math.Abs(time), 1) * frameRate * kTimeEpsilon; + } + + public static bool OnFrameBoundary(double time, double frameRate, double epsilon) + { + ValidateFrameRate(frameRate); + + double exact = ToExactFrames(time, frameRate); + double rounded = Math.Round(exact); + + return Math.Abs(exact - rounded) < epsilon; + } + + public static double RoundToFrame(double time, double frameRate) + { + ValidateFrameRate(frameRate); + + var frameBefore = (int)Math.Floor(time * frameRate) / frameRate; + var frameAfter = (int)Math.Ceiling(time * frameRate) / frameRate; + + return Math.Abs(time - frameBefore) < Math.Abs(time - frameAfter) ? frameBefore : frameAfter; + } + + public static string TimeAsFrames(double timeValue, double frameRate, string format = "F2") + { + if (OnFrameBoundary(timeValue, frameRate)) // make integral values when on time borders + return ToFrames(timeValue, frameRate).ToString(); + return ToExactFrames(timeValue, frameRate).ToString(format); + } + + public static string TimeAsTimeCode(double timeValue, double frameRate, string format = "F2") + { + ValidateFrameRate(frameRate); + + int intTime = (int)Math.Abs(timeValue); + + int hours = intTime / 3600; + int minutes = (intTime % 3600) / 60; + int seconds = intTime % 60; + + string result; + string sign = timeValue < 0 ? "-" : string.Empty; + if (hours > 0) + result = hours + ":" + minutes.ToString("D2") + ":" + seconds.ToString("D2"); + else if (minutes > 0) + result = minutes + ":" + seconds.ToString("D2"); + else + result = seconds.ToString(); + + int frameDigits = (int)Math.Floor(Math.Log10(frameRate) + 1); + + // Add partial digits on the frame if needed. + // we are testing the original value (not the truncated), because the truncation can cause rounding errors leading + // to invalid strings for items on frame boundaries + string frames = (ToFrames(timeValue, frameRate) - ToFrames(intTime, frameRate)).ToString().PadLeft(frameDigits, '0'); + if (!OnFrameBoundary(timeValue, frameRate)) + { + string decimals = ToExactFrames(timeValue, frameRate).ToString(format); + int decPlace = decimals.IndexOf('.'); + if (decPlace >= 0) + frames += " [" + decimals.Substring(decPlace) + "]"; + } + + return sign + result + ":" + frames; + } + + // Given a time code string, return the time in seconds + // 1.5 -> 1.5 seconds + // 1:1.5 -> 1 minute, 1.5 seconds + // 1:1[.5] -> 1 second, 1.5 frames + // 2:3:4 -> 2 minutes, 3 seconds, 4 frames + // 1[.6] -> 1.6 frames + public static double ParseTimeCode(string timeCode, double frameRate, double defaultValue) + { + timeCode = RemoveChar(timeCode, c => char.IsWhiteSpace(c)); + string[] sections = timeCode.Split(':'); + if (sections.Length == 0 || sections.Length > 4) + return defaultValue; + + int hours = 0; + int minutes = 0; + double seconds = 0; + double frames = 0; + + try + { + // depending on the format of the last numbers + // seconds format + string lastSection = sections[sections.Length - 1]; + if (Regex.Match(lastSection, @"^\d+\.\d+$").Success) + { + seconds = double.Parse(lastSection); + if (sections.Length > 3) return defaultValue; + if (sections.Length > 1) minutes = int.Parse(sections[sections.Length - 2]); + if (sections.Length > 2) hours = int.Parse(sections[sections.Length - 3]); + } + // frame formats + else + { + if (Regex.Match(lastSection, @"^\d+\[\.\d+\]$").Success) + { + string stripped = RemoveChar(lastSection, c => c == '[' || c == ']'); + frames = double.Parse(stripped); + } + else if (Regex.Match(lastSection, @"^\d*$").Success) + { + frames = int.Parse(lastSection); + } + else + { + return defaultValue; + } + + if (sections.Length > 1) seconds = int.Parse(sections[sections.Length - 2]); + if (sections.Length > 2) minutes = int.Parse(sections[sections.Length - 3]); + if (sections.Length > 3) hours = int.Parse(sections[sections.Length - 4]); + } + } + catch (FormatException) + { + return defaultValue; + } + + return frames / frameRate + seconds + minutes * 60 + hours * 3600; + } + + // fixes rounding errors from using single precision for length + public static double GetAnimationClipLength(AnimationClip clip) + { + if (clip == null || clip.empty) + return 0; + + double length = clip.length; + if (clip.frameRate > 0) + { + double frames = Mathf.Round(clip.length * clip.frameRate); + length = frames / clip.frameRate; + } + return length; + } + + static string RemoveChar(string str, Func<char, bool> charToRemoveFunc) + { + var len = str.Length; + var src = str.ToCharArray(); + var dstIdx = 0; + for (var i = 0; i < len; i++) + { + if (!charToRemoveFunc(src[i])) + src[dstIdx++] = src[i]; + } + return new string(src, 0, dstIdx); + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/TimeUtility.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/TimeUtility.cs.meta new file mode 100644 index 0000000..ff1d820 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/TimeUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f779e779d62b5ca49b658236c337845d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/TimelineCreateUtilities.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/TimelineCreateUtilities.cs new file mode 100644 index 0000000..0870e40 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/TimelineCreateUtilities.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections.Generic; +#if UNITY_EDITOR +using UnityEditor; +#endif + +namespace UnityEngine.Timeline +{ + static class TimelineCreateUtilities + { + // based off of ObjectNames.GetUniqueName, but can exist in runtime + public static string GenerateUniqueActorName(List<ScriptableObject> tracks, string name) + { + if (!tracks.Exists(x => ((object)x) != null && x.name == name)) + return name; + + int numberInParentheses = 0; + string baseName = name; + + if (!string.IsNullOrEmpty(name) && name[name.Length - 1] == ')') + { + int index = name.LastIndexOf('('); + if (index > 0) + { + string numberString = name.Substring(index + 1, name.Length - index - 2); + if (int.TryParse(numberString, out numberInParentheses)) + { + numberInParentheses++; + baseName = name.Substring(0, index); + } + } + } + + baseName = baseName.TrimEnd(); + + for (int i = numberInParentheses; i < numberInParentheses + 5000; i++) + { + if (i > 0) + { + string result = string.Format("{0} ({1})", baseName, i); + if (!tracks.Exists(x => ((object)x) != null && x.name == result)) + return result; + } + } + + // Fallback + return name; + } + + public static void SaveAssetIntoObject(Object childAsset, Object masterAsset) + { + if (childAsset == null || masterAsset == null) + return; + + if ((masterAsset.hideFlags & HideFlags.DontSave) != 0) + { + childAsset.hideFlags |= HideFlags.DontSave; + } + else + { + childAsset.hideFlags |= HideFlags.HideInHierarchy; +#if UNITY_EDITOR + if (!AssetDatabase.Contains(childAsset) && AssetDatabase.Contains(masterAsset)) + AssetDatabase.AddObjectToAsset(childAsset, masterAsset); +#endif + } + } + + public static AnimationClip CreateAnimationClipForTrack(string name, TrackAsset track, bool isLegacy) + { + var timelineAsset = track != null ? track.timelineAsset : null; + var trackFlags = track != null ? track.hideFlags : HideFlags.None; + + var curves = new AnimationClip + { + legacy = isLegacy, + + name = name, + + frameRate = timelineAsset == null + ? TimelineAsset.EditorSettings.kDefaultFps + : timelineAsset.editorSettings.fps + }; + + SaveAssetIntoObject(curves, timelineAsset); + curves.hideFlags = trackFlags & ~HideFlags.HideInHierarchy; // Never hide in hierarchy + + TimelineUndo.RegisterCreatedObjectUndo(curves, "Create Curves"); + + return curves; + } + + public static bool ValidateParentTrack(TrackAsset parent, Type childType) + { + if (childType == null || !typeof(TrackAsset).IsAssignableFrom(childType)) + return false; + + // no parent is valid for any type + if (parent == null) + return true; + + // A track supports layers if it implements ILayerable. Only supported for parents that are + // the same exact type as the child class, and 1 level of nesting only + if (parent is ILayerable && !parent.isSubTrack && parent.GetType() == childType) + return true; + + var attr = Attribute.GetCustomAttribute(parent.GetType(), typeof(SupportsChildTracksAttribute)) as SupportsChildTracksAttribute; + if (attr == null) + return false; + + // group track case, accepts all + if (attr.childType == null) + return true; + + // specific case. Specifies nesting level + if (childType == attr.childType) + { + int nestCount = 0; + var p = parent; + while (p != null && p.isSubTrack) + { + nestCount++; + p = p.parent as TrackAsset; + } + + return nestCount < attr.levels; + } + return false; + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/TimelineCreateUtilities.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/TimelineCreateUtilities.cs.meta new file mode 100644 index 0000000..f81aa91 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/TimelineCreateUtilities.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 40cb137d0e9816e48a4141ed13afedad +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/TimelineUndo.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/TimelineUndo.cs new file mode 100644 index 0000000..b6392f0 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/TimelineUndo.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using UnityEngine.Playables; + +#if UNITY_EDITOR +using UnityEditor; +#endif + +namespace UnityEngine.Timeline +{ + static class TimelineUndo + { + public static void PushDestroyUndo(TimelineAsset timeline, Object thingToDirty, Object objectToDestroy, string operation) + { +#if UNITY_EDITOR + if (objectToDestroy == null || !DisableUndoGuard.enableUndo) + return; + + if (thingToDirty != null) + EditorUtility.SetDirty(thingToDirty); + + if (timeline != null) + EditorUtility.SetDirty(timeline); + + Undo.DestroyObjectImmediate(objectToDestroy); +#else + if (objectToDestroy != null) + Object.Destroy(objectToDestroy); +#endif + } + + [Conditional("UNITY_EDITOR")] + public static void PushUndo(Object thingToDirty, string operation) + { +#if UNITY_EDITOR + if (thingToDirty != null && DisableUndoGuard.enableUndo) + { + var track = thingToDirty as TrackAsset; + if (track != null) + track.MarkDirty(); + + EditorUtility.SetDirty(thingToDirty); + Undo.RegisterCompleteObjectUndo(thingToDirty, "Timeline " + operation); + } +#endif + } + + [Conditional("UNITY_EDITOR")] + public static void RegisterCreatedObjectUndo(Object thingCreated, string operation) + { +#if UNITY_EDITOR + if (DisableUndoGuard.enableUndo) + { + Undo.RegisterCreatedObjectUndo(thingCreated, "Timeline " + operation); + } +#endif + } + +#if UNITY_EDITOR + public struct DisableUndoGuard : IDisposable + { + internal static bool enableUndo = true; + static readonly Stack<bool> m_UndoStateStack = new Stack<bool>(); + bool m_Disposed; + public DisableUndoGuard(bool disable) + { + m_Disposed = false; + m_UndoStateStack.Push(enableUndo); + enableUndo = !disable; + } + + public void Dispose() + { + if (!m_Disposed) + { + if (m_UndoStateStack.Count == 0) + { + Debug.LogError("UnMatched DisableUndoGuard calls"); + enableUndo = true; + return; + } + enableUndo = m_UndoStateStack.Pop(); + m_Disposed = true; + } + } + } +#endif + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/TimelineUndo.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/TimelineUndo.cs.meta new file mode 100644 index 0000000..c62c751 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/TimelineUndo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1f2a7e0d1b6bbba408a41e206945c23c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/WeightUtility.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/WeightUtility.cs new file mode 100644 index 0000000..22db909 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/WeightUtility.cs @@ -0,0 +1,30 @@ +using UnityEngine.Playables; + +namespace UnityEngine.Timeline +{ + static class WeightUtility + { + // Given a mixer, normalizes the mixer if required + // returns the output weight that should be applied to the mixer as input + public static float NormalizeMixer(Playable mixer) + { + if (!mixer.IsValid()) + return 0; + int count = mixer.GetInputCount(); + float weight = 0.0f; + for (int c = 0; c < count; c++) + { + weight += mixer.GetInputWeight(c); + } + + if (weight > Mathf.Epsilon && weight < 1) + { + for (int c = 0; c < count; c++) + { + mixer.SetInputWeight(c, mixer.GetInputWeight(c) / weight); + } + } + return Mathf.Clamp01(weight); + } + } +} diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/WeightUtility.cs.meta b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/WeightUtility.cs.meta new file mode 100644 index 0000000..bf2c55d --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Utilities/WeightUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e7a505b341283e14696e86433a5b1ae9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: |
