2022-01-12 10:06:03 +03:00
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>
/// 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.
/// <seealso cref="UnityEngine.Timeline.SignalEmitter"/>
/// <seealso cref="UnityEngine.Timeline.SignalAsset"/>
public class SignalReceiver : MonoBehaviour , INotificationReceiver
{
[SerializeField]
EventKeyValue m_Events = new EventKeyValue ( ) ;
/// <summary>
/// Called when a notification is sent.
/// </summary>
2022-01-12 10:39:15 +03:00
/// <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>
2022-01-12 10:06:03 +03:00
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></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 ; }
}
}
}
}