123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- using System;
- using System.Collections.Generic;
- using UnityEngine.Playables;
- namespace UnityEngine.Timeline
- {
-
-
-
-
- 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;
-
-
-
-
-
-
- public Playable timeSource
- {
- set { m_TimeSource = value; }
- }
-
-
-
-
-
-
-
- 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;
- }
-
-
-
-
-
-
-
- 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;
- }
-
-
-
-
- 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();
- }
-
-
-
-
-
- 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;
- }
- }
- }
- }
- }
-
-
-
-
-
-
-
-
- public override void PrepareFrame(Playable playable, FrameData info)
- {
-
- if (info.evaluationType == FrameData.EvaluationType.Evaluate)
- {
- return;
- }
- SyncDurationWithExternalSource(playable);
- SortNotifications();
- var currentTime = playable.GetTime();
-
- 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;
-
- 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;
- }
- }
- }
|