You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
253 lines
9.1 KiB
C#
253 lines
9.1 KiB
C#
1 year ago
|
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"/>
|
||
|
[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></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; }
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|