2019-04-16 16:32:17 -04:00
using System ;
using System.Collections.Generic ;
2018-10-30 15:05:06 -04:00
using UnityEngine ;
2019-04-07 10:03:16 -04:00
using UnityEngine.Serialization ;
2018-10-30 15:05:06 -04:00
namespace UnityAtoms
{
2019-10-15 16:21:56 -04:00
/// <summary>
/// Generic base class for Variables. Inherits from `AtomBaseVariable<T>`.
/// </summary>
/// <typeparam name="T">The Variable value type.</typeparam>
/// <typeparam name="E1">Event of type `AtomEvent<T>`.</typeparam>
/// <typeparam name="E2">Event of type `AtomEvent<T, T>`.</typeparam>
2019-10-14 10:51:54 -04:00
[EditorIcon("atom-icon-lush")]
2019-09-30 16:55:33 -04:00
public abstract class AtomVariable < T , E1 , E2 > : AtomBaseVariable < T > ,
2019-10-14 20:16:11 -04:00
ISerializationCallbackReceiver
2019-09-25 15:05:06 -04:00
where E1 : AtomEvent < T >
where E2 : AtomEvent < T , T >
2018-10-30 15:05:06 -04:00
{
2019-10-15 16:21:56 -04:00
/// <summary>
/// The Variable value as a property.
/// </summary>
/// <returns>Get or set the Variable value.</returns>
2019-04-08 13:46:02 -04:00
public override T Value { get { return _value ; } set { SetValue ( value ) ; } }
2019-10-15 16:21:56 -04:00
/// <summary>
/// The inital value of the Variable.
/// </summary>
2019-04-08 13:46:02 -04:00
[SerializeField]
2019-10-03 15:34:57 -04:00
private T _initialValue = default ( T ) ;
2018-10-30 15:05:06 -04:00
2019-10-15 16:21:56 -04:00
/// <summary>
/// The value the Variable had before its value got changed last time.
/// </summary>
/// <value></value>
2019-04-07 10:03:16 -04:00
public T OldValue { get { return _oldValue ; } }
2018-10-30 15:05:06 -04:00
2019-04-07 10:03:16 -04:00
[FormerlySerializedAs("oldValue")]
2018-10-30 15:05:06 -04:00
[SerializeField]
2019-04-07 10:03:16 -04:00
private T _oldValue ;
2018-10-30 15:05:06 -04:00
2019-10-15 16:21:56 -04:00
/// <summary>
/// Changed Event triggered when the Variable value gets changed.
/// </summary>
2018-10-30 15:05:06 -04:00
public E1 Changed ;
2019-10-15 16:21:56 -04:00
/// <summary>
/// Changed with history Event triggered when the Variable value gets changed.
/// </summary>
2018-10-30 15:05:06 -04:00
public E2 ChangedWithHistory ;
protected abstract bool AreEqual ( T first , T second ) ;
2019-03-17 18:43:20 -04:00
private void OnEnable ( )
{
if ( Changed = = null ) return ;
Changed . Raise ( Value ) ;
}
2019-10-15 16:21:56 -04:00
/// <summary>
/// Reset the Variable to its `_initalValue`.
/// </summary>
/// <param name="shouldTriggerEvents">Set to `true` if Events should be triggered on reset, otherwise `false`.</param>
2019-10-14 10:39:22 -04:00
public override sealed void Reset ( bool shouldTriggerEvents = false )
2019-09-29 18:26:53 -04:00
{
2019-09-30 16:55:33 -04:00
if ( ! shouldTriggerEvents )
{
_oldValue = _value ;
_value = _initialValue ;
}
else
{
SetValue ( _initialValue ) ;
}
2019-09-29 18:26:53 -04:00
}
2019-10-15 16:21:56 -04:00
/// <summary>
/// Set the Variable value.
/// </summary>
/// <param name="newValue">The new value to set.</param>
/// <returns>`true` if the value got changed, otherwise `false`.</returns>
2019-04-07 05:52:07 -04:00
public bool SetValue ( T newValue )
2018-10-30 15:05:06 -04:00
{
2019-04-08 13:46:02 -04:00
if ( ! AreEqual ( _value , newValue ) )
2018-10-30 15:05:06 -04:00
{
2019-04-08 13:46:02 -04:00
_oldValue = _value ;
_value = newValue ;
if ( Changed ! = null ) { Changed . Raise ( _value ) ; }
if ( ChangedWithHistory ! = null ) { ChangedWithHistory . Raise ( _value , _oldValue ) ; }
2019-04-05 07:40:26 -04:00
return true ;
2018-10-30 15:05:06 -04:00
}
2019-04-05 07:40:26 -04:00
return false ;
2018-10-30 15:05:06 -04:00
}
2019-10-15 16:21:56 -04:00
/// <summary>
/// Set the Variable value.
/// </summary>
/// <param name="variable">The value to set provided from another Variable.</param>
/// <returns>`true` if the value got changed, otherwise `false`.</returns>
2019-09-25 15:05:06 -04:00
public bool SetValue ( AtomVariable < T , E1 , E2 > variable )
2018-10-30 15:05:06 -04:00
{
return SetValue ( variable . Value ) ;
}
2019-04-08 13:46:02 -04:00
public void OnBeforeSerialize ( ) { }
public void OnAfterDeserialize ( ) { _value = _initialValue ; }
2019-04-16 16:32:17 -04:00
#region Observable
2019-10-15 16:21:56 -04:00
/// <summary>
/// Turn the Variable's change Event into an `IObservable<T>`. Makes the Variable's change Event compatible with for example UniRx.
/// </summary>
/// <returns>The Variable's change Event as an `IObservable<T>`.</returns>
2019-04-16 16:32:17 -04:00
public IObservable < T > ObserveChange ( )
{
if ( Changed = = null )
{
throw new Exception ( "You must assign a Changed event in order to observe variable changes." ) ;
}
return new ObservableEvent < T > ( Changed . Register , Changed . Unregister ) ;
}
2019-04-21 07:51:20 -04:00
2019-10-15 16:21:56 -04:00
/// <summary>
/// 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.
/// </summary>
/// <returns>The Variable's change Event as an `IObservable<T, T>`.</returns>
2019-04-21 07:51:20 -04:00
public IObservable < ValueTuple < T , T > > ObserveChangeWithHistory ( )
{
if ( ChangedWithHistory = = null )
{
throw new Exception ( "You must assign a ChangedWithHistory event in order to observe variable changes." ) ;
}
return new ObservableEvent < T , T , ValueTuple < T , T > > (
register : ChangedWithHistory . Register ,
unregister : ChangedWithHistory . Unregister ,
createCombinedModel : ( n , o ) = > new ValueTuple < T , T > ( n , o )
) ;
}
2019-04-16 16:32:17 -04:00
#endregion // Observable
2018-10-30 15:05:06 -04:00
}
2019-04-05 07:40:26 -04:00
}