using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Playables;
namespace UnityEngine.Timeline
{
///
/// Listens for emitted signals and reacts depending on its defined reactions.
///
/// 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.
///
///
public class SignalReceiver : MonoBehaviour, INotificationReceiver
{
[SerializeField]
EventKeyValue m_Events = new EventKeyValue();
///
/// Called when a notification is sent.
///
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();
}
}
}
///
/// Defines a new reaction for a SignalAsset.
///
/// The SignalAsset for which the reaction is being defined.
/// The UnityEvent that describes the reaction.
/// Thrown when the asset is null.
/// Thrown when the SignalAsset is already registered with this receiver.
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);
}
///
/// Appends a null SignalAsset with a reaction specified by the UnityEvent.
///
/// The new reaction to be appended.
/// The index of the appended reaction.
/// Multiple null assets are valid.
public int AddEmptyReaction(UnityEvent reaction)
{
m_Events.Append(null, reaction);
return m_Events.events.Count - 1;
}
///
/// Removes the first occurrence of a SignalAsset.
///
/// The SignalAsset to be removed.
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);
}
///
/// Gets a list of all registered SignalAssets.
///
/// Returns a list of SignalAssets.
public IEnumerable GetRegisteredSignals()
{
return m_Events.signals;
}
///
/// Gets the first UnityEvent associated with a SignalAsset.
///
/// A SignalAsset defining the signal.
/// Returns the reaction associated with a SignalAsset. Returns null if the signal asset does not exist.
public UnityEvent GetReaction(SignalAsset key)
{
UnityEvent ret;
if (m_Events.TryGetValue(key, out ret))
{
return ret;
}
return null;
}
///
/// Returns the count of registered SignalAssets.
///
///
public int Count()
{
return m_Events.signals.Count;
}
///
/// Replaces the SignalAsset associated with a reaction at a specific index.
///
/// The index of the reaction.
/// The replacement SignalAsset.
/// Thrown when the replacement SignalAsset is already registered to this SignalReceiver.
/// The new SignalAsset can be null.
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.");
}
///
/// Removes the SignalAsset and reaction at a specific index.
///
/// The index of the SignalAsset to be removed.
public void RemoveAtIndex(int idx)
{
if (idx < 0 || idx > m_Events.signals.Count - 1)
throw new IndexOutOfRangeException();
m_Events.Remove(idx);
}
///
/// Replaces the reaction at a specific index with a new UnityEvent.
///
/// The index of the reaction to be replaced.
/// The replacement reaction.
/// Thrown when the replacement reaction is null.
public void ChangeReactionAtIndex(int idx, UnityEvent reaction)
{
if (idx < 0 || idx > m_Events.events.Count - 1)
throw new IndexOutOfRangeException();
m_Events.events[idx] = reaction;
}
///
/// Gets the reaction at a specific index.
///
/// The index of the reaction.
/// Returns a reaction.
public UnityEvent GetReactionAtIndex(int idx)
{
if (idx < 0 || idx > m_Events.events.Count - 1)
throw new IndexOutOfRangeException();
return m_Events.events[idx];
}
///
/// Gets the SignalAsset at a specific index
///
/// The index of the SignalAsset.
/// Returns a SignalAsset.
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 m_Signals = new List();
[SerializeField, CustomSignalEventDrawer]
List m_Events = new List();
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 signals
{
get { return m_Signals; }
}
public List events
{
get { return m_Events; }
}
}
}
}