// ------------------------------------------------------------------------------------------------------
// Heavily inspired by Ryan Hipple, 10/04/17 from Unite 2017 - Game Architecture with Scriptable Objects
// ------------------------------------------------------------------------------------------------------
using System;
using UnityEngine.Events;
using Xprees.Core;
using Xprees.Variables.Utils;
namespace Xprees.Variables.Base
{
///
/// Base class for all variable references used in the game. It can either use an inlined value or reference a VariableBaseSO Scriptable Object. The Value property abstracts this choice away, so users of ReferenceBase don't have to care about it.
///
/// Unity Serializable
[Serializable]
public class ReferenceBase : IResettable
{
private T _defaultInlinedValue; // Used to reset state of inlined value
public bool useInlined = true;
public T inlinedValue;
public VariableBaseSO variable;
// Internal event for inlined value changes, since VariableBaseSO already has its own onValueChanged event.
private UnityAction _onInlinedValueChanged;
// ReSharper disable once InconsistentNaming
/// Event invoked when Value changes.
public event UnityAction onValueChanged
{
add
{
var shouldRedirectToVarEvent = !useInlined && variable != null;
if (shouldRedirectToVarEvent)
{
variable.onValueChanged += value;
return;
}
_onInlinedValueChanged += value;
}
remove
{
var shouldRedirectToVarEvent = !useInlined && variable != null;
if (shouldRedirectToVarEvent)
{
variable.onValueChanged -= value;
return;
}
_onInlinedValueChanged -= value;
}
}
public ReferenceBase()
{
}
public ReferenceBase(T value)
{
useInlined = true;
inlinedValue = value;
_defaultInlinedValue = value;
}
public T Value
{
get => useInlined ? inlinedValue : variable.CurrentValue;
set
{
if (useInlined)
{
inlinedValue = value;
_onInlinedValueChanged?.Invoke(value); // Invoke inlined value change event
return;
}
// VariableBaseSO will invoke its own onValueChanged event, so no need to invoke here.
variable.SetValue(value);
}
}
public static implicit operator T(ReferenceBase reference) => reference != null ? reference.Value : default;
public virtual void BackupStartState()
{
if (!useInlined) return; // Variables does that by themselves
_defaultInlinedValue = CloningTools.Clone(inlinedValue);
}
public virtual void ResetState()
{
if (useInlined)
{
inlinedValue = CloningTools.Clone(_defaultInlinedValue);
return;
}
variable?.ResetState();
}
}
}