From c55fba8ab2a1c9d3df65eda4a5a1e957f4aa1f78 Mon Sep 17 00:00:00 2001 From: Andrew Lee Date: Sun, 19 Apr 2020 17:19:32 -0400 Subject: Inital commit --- .../Runtime/Playables/DirectorControlPlayable.cs | 206 +++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/DirectorControlPlayable.cs (limited to 'Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Playables/DirectorControlPlayable.cs') 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 +{ + /// + /// Playable Behaviour used to control a PlayableDirector. + /// + /// + /// This playable is used to control other PlayableDirector components from a Timeline sequence. + /// + public class DirectorControlPlayable : PlayableBehaviour + { + /// + /// The PlayableDirector being controlled by this PlayableBehaviour + /// + public PlayableDirector director; + + private bool m_SyncTime = false; + + private double m_AssetDuration = double.MaxValue; + + /// + /// Creates a Playable with a DirectorControlPlayable attached + /// + /// The graph to inject the playable into + /// The director to control + /// Returns a Playable with a DirectorControlPlayable attached + public static ScriptPlayable Create(PlayableGraph graph, PlayableDirector director) + { + if (director == null) + return ScriptPlayable.Null; + + var handle = ScriptPlayable.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(); + } + + /// + /// This function is called during the PrepareFrame phase of the PlayableGraph. + /// + /// The Playable that owns the current PlayableBehaviour. + /// A FrameData structure that contains information about the current frame context. + 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()); + } + + /// + /// This function is called when the Playable play state is changed to Playables.PlayState.Playing. + /// + /// The Playable that owns the current PlayableBehaviour. + /// A FrameData structure that contains information about the current frame context. + public override void OnBehaviourPlay(Playable playable, FrameData info) + { + m_SyncTime = true; + + if (director != null && director.playableAsset != null) + m_AssetDuration = director.playableAsset.duration; + } + + /// + /// This function is called when the Playable play state is changed to PlayState.Paused. + /// + /// The playable this behaviour is attached to. + /// A FrameData structure that contains information about the current frame context. + 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(); + } + } + + /// + /// This function is called during the ProcessFrame phase of the PlayableGraph. + /// + /// The playable this behaviour is attached to. + /// A FrameData structure that contains information about the current frame context. + /// unused + 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; + } + } + } +} -- cgit v1.2.3