255 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			255 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| 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>
 | |
|     /// <remarks>
 | |
|     /// 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.
 | |
|     /// </remarks>
 | |
|     /// <seealso cref="UnityEngine.Timeline.SignalEmitter"/>
 | |
|     /// <seealso cref="UnityEngine.Timeline.SignalAsset"/>
 | |
|     [TimelineHelpURL(typeof(SignalReceiver))]
 | |
|     public class SignalReceiver : MonoBehaviour, INotificationReceiver
 | |
|     {
 | |
|         [SerializeField]
 | |
|         EventKeyValue m_Events = new EventKeyValue();
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Called when a notification is sent.
 | |
|         /// </summary>
 | |
|         /// <param name="origin">The playable that sent the notification.</param>
 | |
|         /// <param name="notification">The received notification. Only notifications of type <see cref="SignalEmitter"/> will be processed.</param>
 | |
|         /// <param name="context">User defined data that depends on the type of notification. Uses this to pass necessary information that can change with each invocation.</param>
 | |
|         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>The count of registered SignalAssets</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; }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 |