using System; using System.Collections.Generic; using UnityEngine; namespace UnityAtoms { /// /// Generic base class for Events. Inherits from `AtomEventBase`. /// /// The type for this Event. [EditorIcon("atom-icon-cherry")] public class AtomEvent : AtomEventBase { public T InspectorRaiseValue { get => _inspectorRaiseValue; } [SerializeField] private event Action _onEvent; /// /// The event replays the specified number of old values to new subscribers. Works like a ReplaySubject in Rx. /// [SerializeField] [Range(0, 10)] [Tooltip("The number of old values (between 0-10) being replayed when someone subscribes to this Event.")] private int _replayBufferSize = 1; private Queue _replayBuffer = new Queue(); private void OnDisable() { // Clear all delegates when exiting play mode if (_onEvent != null) { var invocationList = _onEvent.GetInvocationList(); foreach (var d in invocationList) { _onEvent -= (Action)d; } } } /// /// Used when raising values from the inspector for debugging purposes. /// [SerializeField] [Tooltip("Value that will be used when using the Raise button in the editor inspector.")] private T _inspectorRaiseValue = default(T); /// /// Raise the Event. /// /// The value associated with the Event. public void Raise(T item) { base.Raise(); _onEvent?.Invoke(item); AddToReplayBuffer(item); } /// /// Register handler to be called when the Event triggers. /// /// The handler. public void Register(Action action) { _onEvent += action; ReplayBuffer(action); } /// /// Unregister handler that was registered using the `Register` method. /// /// The handler. public void Unregister(Action action) { _onEvent -= action; } /// /// Register a Listener that in turn trigger all its associated handlers when the Event triggers. /// /// The Listener to register. public void RegisterListener(IAtomListener listener) { _onEvent += listener.OnEventRaised; ReplayBuffer(listener.OnEventRaised); } /// /// Unregister a listener that was registered using the `RegisterListener` method. /// /// The Listener to unregister. public void UnregisterListener(IAtomListener listener) { _onEvent -= listener.OnEventRaised; } #region Observable /// /// Turn the Event into an `IObservable<T>`. Makes Events compatible with for example UniRx. /// /// The Event as an `IObservable<T>`. public IObservable Observe() { return new ObservableEvent(Register, Unregister); } #endregion // Observable private void AddToReplayBuffer(T item) { if (_replayBufferSize > 0) { while (_replayBuffer.Count >= _replayBufferSize) { _replayBuffer.Dequeue(); } _replayBuffer.Enqueue(item); } } private void ReplayBuffer(Action action) { if (_replayBufferSize > 0 && _replayBuffer.Count > 0) { var enumerator = _replayBuffer.GetEnumerator(); try { while (enumerator.MoveNext()) { action(enumerator.Current); } } finally { enumerator.Dispose(); } } } } }