namespace Zinnia.Data.Type.Observer
{
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using Zinnia.Extension;
///
/// The basis for all Observable Property types.
///
public abstract class ObservableProperty : MonoBehaviour { }
///
/// Allows observing changes to a property.
///
/// The data type.
/// The type to use.
public abstract class ObservableProperty : ObservableProperty where TEvent : UnityEvent, new()
{
///
/// Emitted when the property value is set and modified from its previous value.
///
[Header("Observable Events")]
public TEvent Modified = new TEvent();
///
/// Emitted when the property value is set and unmodified from its previous value.
///
public TEvent Unmodified = new TEvent();
///
/// Emitted when the property value is set and modified back to the data type's default value.
///
public TEvent Defaulted = new TEvent();
///
/// Emitted when the property value is set and modified from the data type's default value to a defined value.
///
public TEvent Defined = new TEvent();
[Header("Property Settings")]
[Tooltip("The observed data.")]
[SerializeField]
private TType data;
///
/// The observed data.
///
public TType Data
{
get
{
return data;
}
set
{
if (this.IsMemberChangeAllowed())
{
OnBeforeDataChange();
}
data = value;
if (this.IsMemberChangeAllowed())
{
OnAfterDataChange();
}
}
}
[Tooltip("Whether to observe data changes that were made when the component was disabled and subsequently re-enabled. Events are not raised when component is disabled.")]
[SerializeField]
private bool observeChangesFromDisabledState = true;
///
/// Whether to observe data changes that were made when the component was disabled and subsequently re-enabled. Events are not raised when component is disabled.
///
public bool ObserveChangesFromDisabledState
{
get
{
return observeChangesFromDisabledState;
}
set
{
observeChangesFromDisabledState = value;
}
}
///
/// The previous value of the .
///
protected TType previousDataValue;
///
/// Whether to raise the unmodified event.
///
protected bool shouldRaiseUnmodifiedEvent;
///
/// Resets the back to its default value.
///
public virtual void ResetToDefault()
{
Data = default;
}
protected virtual void Awake()
{
CacheExistingValue();
}
protected virtual void OnEnable()
{
shouldRaiseUnmodifiedEvent = false;
if (ObserveChangesFromDisabledState)
{
CheckForChanges();
}
shouldRaiseUnmodifiedEvent = true;
}
protected virtual void OnDisable()
{
CacheExistingValue();
}
///
/// Determines whether the two given values are equal.
///
/// The to compare against.
/// The to compare with.
/// if the two values are considered equal.
protected virtual bool Equals(TType a, TType b)
{
return EqualityComparer.Default.Equals(a, b);
}
///
/// Caches the existing value.
///
protected virtual void CacheExistingValue()
{
previousDataValue = Data;
}
///
/// Checks for changes from the current value to the previous value.
///
protected virtual void CheckForChanges()
{
if (!this.IsValidState())
{
return;
}
if (Equals(Data, previousDataValue))
{
if (shouldRaiseUnmodifiedEvent)
{
Unmodified?.Invoke(Data);
}
}
else
{
if (Equals(previousDataValue, default) && !Equals(Data, default))
{
Defined?.Invoke(Data);
}
Modified?.Invoke(Data);
if (!Equals(previousDataValue, default) && Equals(Data, default))
{
Defaulted?.Invoke(Data);
}
}
CacheExistingValue();
}
///
/// Called before has been changed.
///
protected virtual void OnBeforeDataChange()
{
CacheExistingValue();
}
///
/// Called after has been changed.
///
protected virtual void OnAfterDataChange()
{
CheckForChanges();
}
}
}