Initial Commit
This commit is contained in:
parent
53eb92e9af
commit
270ab7d11f
15341 changed files with 700234 additions and 0 deletions
|
@ -0,0 +1,258 @@
|
|||
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();
|
||||
var currentTime = playable.GetTime();
|
||||
for (var i = 0; i < m_Notifications.Count; i++)
|
||||
{
|
||||
// case 1257208 - when a timeline is _resumed_, only reset notifications after the resumed time
|
||||
if (m_Notifications[i].time > currentTime && !m_Notifications[i].triggerOnce)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue