using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Serialization; namespace UnityAtoms { /// /// Generic base class for Variables. Inherits from `AtomBaseVariable<T>`. /// /// The Variable value type. /// Event of type `AtomEvent<T>`. /// Event of type `AtomEvent<T, T>`. [EditorIcon("atom-icon-lush")] public abstract class AtomVariable : AtomBaseVariable, ISerializationCallbackReceiver where E1 : AtomEvent where E2 : AtomEvent { /// /// The Variable value as a property. /// /// Get or set the Variable value. public override T Value { get { return _value; } set { SetValue(value); } } /// /// The inital value of the Variable. /// [SerializeField] private T _initialValue = default(T); /// /// The value the Variable had before its value got changed last time. /// /// public T OldValue { get { return _oldValue; } } [FormerlySerializedAs("oldValue")] [SerializeField] private T _oldValue; /// /// Changed Event triggered when the Variable value gets changed. /// public E1 Changed; /// /// Changed with history Event triggered when the Variable value gets changed. /// public E2 ChangedWithHistory; protected abstract bool AreEqual(T first, T second); private void OnEnable() { if (Changed == null) return; Changed.Raise(Value); } /// /// Reset the Variable to its `_initalValue`. /// /// Set to `true` if Events should be triggered on reset, otherwise `false`. public override sealed void Reset(bool shouldTriggerEvents = false) { if (!shouldTriggerEvents) { _oldValue = _value; _value = _initialValue; } else { SetValue(_initialValue); } } /// /// Set the Variable value. /// /// The new value to set. /// `true` if the value got changed, otherwise `false`. public bool SetValue(T newValue) { if (!AreEqual(_value, newValue)) { _oldValue = _value; _value = newValue; if (Changed != null) { Changed.Raise(_value); } if (ChangedWithHistory != null) { ChangedWithHistory.Raise(_value, _oldValue); } return true; } return false; } /// /// Set the Variable value. /// /// The value to set provided from another Variable. /// `true` if the value got changed, otherwise `false`. public bool SetValue(AtomVariable variable) { return SetValue(variable.Value); } public void OnBeforeSerialize() { } public void OnAfterDeserialize() { _value = _initialValue; } #region Observable /// /// Turn the Variable's change Event into an `IObservable<T>`. Makes the Variable's change Event compatible with for example UniRx. /// /// The Variable's change Event as an `IObservable<T>`. public IObservable ObserveChange() { if (Changed == null) { throw new Exception("You must assign a Changed event in order to observe variable changes."); } return new ObservableEvent(Changed.Register, Changed.Unregister); } /// /// Turn the Variable's change with history Event into an `IObservable<T, T>`. Makes the Variable's change with history Event compatible with for example UniRx. /// /// The Variable's change Event as an `IObservable<T, T>`. public IObservable> ObserveChangeWithHistory() { if (ChangedWithHistory == null) { throw new Exception("You must assign a ChangedWithHistory event in order to observe variable changes."); } return new ObservableEvent>( register: ChangedWithHistory.Register, unregister: ChangedWithHistory.Unregister, createCombinedModel: (n, o) => new ValueTuple(n, o) ); } #endregion // Observable } }