summaryrefslogtreecommitdiff
path: root/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Control/ControlPlayableAsset.cs
diff options
context:
space:
mode:
authorAndrew Lee <alee14498@protonmail.com>2020-04-19 17:19:32 -0400
committerAndrew Lee <alee14498@protonmail.com>2020-04-19 17:19:32 -0400
commitc55fba8ab2a1c9d3df65eda4a5a1e957f4aa1f78 (patch)
treeee4d51c7c1d633e11f46453ef1edd3c77c4ef9f7 /Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Control/ControlPlayableAsset.cs
downloadProject-Sandbox-c55fba8ab2a1c9d3df65eda4a5a1e957f4aa1f78.tar.gz
Project-Sandbox-c55fba8ab2a1c9d3df65eda4a5a1e957f4aa1f78.tar.bz2
Project-Sandbox-c55fba8ab2a1c9d3df65eda4a5a1e957f4aa1f78.zip
Inital commit
Diffstat (limited to 'Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Control/ControlPlayableAsset.cs')
-rw-r--r--Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Control/ControlPlayableAsset.cs406
1 files changed, 406 insertions, 0 deletions
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);
+ }
+ }
+}