315 lines
6.7 KiB
C#
315 lines
6.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
#if UNITY_EDITOR
|
|
using UnityEditor;
|
|
#endif
|
|
using UnityEngine;
|
|
|
|
namespace RogueUtils.Data
|
|
{
|
|
public abstract class BaseVariableReference<TVariable, TValue> : SubBaseVariableReference where TVariable : BaseVariable<TValue>
|
|
{
|
|
//
|
|
[Multiline]
|
|
[UnityEngine.Serialization.FormerlySerializedAs("description")]
|
|
public string m_Description = "";
|
|
|
|
[SerializeField]
|
|
[HideInInspector]
|
|
protected TVariable m_Variable;
|
|
|
|
#if UNITY_EDITOR
|
|
//
|
|
// This is what appear in the inspector as the variable.
|
|
// It is separate so that Inspector changes can go through the this.Value = new variable instance
|
|
// code path.
|
|
//
|
|
//[ShowInInspector]
|
|
//[OnValueChanged("BaseHandleEditorVariableChange")]
|
|
protected TVariable m_InspectorVariable;
|
|
#endif
|
|
|
|
/// <summary>
|
|
/// The reason for the m_ZeroOnExitPlayMode is that it is an Unity Editor only feature and
|
|
/// resets the Variable value so that Git does not see a bunch of changes to runtime
|
|
/// ScriptableObject Variables
|
|
/// </summary>
|
|
[SerializeField]
|
|
protected bool m_DefaultOnExitPlayMode = false;
|
|
|
|
|
|
private event EventHandler InternalOnVariableChange;
|
|
protected event EventHandler<BaseVariable<TValue>.OnChangeEventArgs> InternalOnReferencedValueChange;
|
|
protected event EventHandler<BaseVariable<TValue>.OnChangeEventArgs> InternalOnValueChange;
|
|
|
|
public event EventHandler OnVariableChange
|
|
{
|
|
// Not thread safe.
|
|
// Will add tracking of subscribers
|
|
add
|
|
{
|
|
InternalOnVariableChange += value;
|
|
}
|
|
|
|
remove
|
|
{
|
|
InternalOnVariableChange -= value;
|
|
}
|
|
}
|
|
|
|
public event EventHandler<BaseVariable<TValue>.OnChangeEventArgs> OnReferencedValueChange
|
|
{
|
|
// Not thread safe.
|
|
// Will add tracking of subscribers
|
|
add
|
|
{
|
|
InternalOnReferencedValueChange += value;
|
|
}
|
|
|
|
remove
|
|
{
|
|
InternalOnReferencedValueChange -= value;
|
|
}
|
|
}
|
|
|
|
public event EventHandler<BaseVariable<TValue>.OnChangeEventArgs> OnValueChange
|
|
{
|
|
// Not thread safe.
|
|
// Will add tracking of subscribers
|
|
add
|
|
{
|
|
InternalOnValueChange += value;
|
|
}
|
|
|
|
remove
|
|
{
|
|
InternalOnValueChange -= value;
|
|
}
|
|
}
|
|
|
|
protected virtual TVariable DefaultVariable
|
|
{
|
|
get => default;
|
|
}
|
|
|
|
public virtual TVariable Variable
|
|
{
|
|
get
|
|
{
|
|
return m_Variable;
|
|
}
|
|
set
|
|
{
|
|
if (m_Variable != null)
|
|
{
|
|
//
|
|
// Remove the listeners from the old variable
|
|
//
|
|
m_Variable.OnChange -= HandleValueChange;
|
|
}
|
|
m_Variable = value;
|
|
|
|
#if UNITY_EDITOR
|
|
m_InspectorVariable = m_Variable;
|
|
#endif
|
|
|
|
if (m_Variable != null)
|
|
{
|
|
m_Variable.OnChange += HandleValueChange;
|
|
}
|
|
|
|
TriggerVariableListeners();
|
|
|
|
//
|
|
// This is also a value change
|
|
//
|
|
if (m_Variable != null)
|
|
{
|
|
HandleValueChange(m_Variable, new BaseVariable<TValue>.OnChangeEventArgs(m_Variable.Value));
|
|
}
|
|
else
|
|
{
|
|
HandleValueChange(m_Variable, new BaseVariable<TValue>.OnChangeEventArgs(default));
|
|
}
|
|
}
|
|
}
|
|
|
|
public virtual TValue Value
|
|
{
|
|
get
|
|
{
|
|
return (m_Variable != null ? m_Variable.Value : default);
|
|
}
|
|
set
|
|
{
|
|
if (m_Variable != null)
|
|
{
|
|
m_Variable.Value = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected virtual void HandleValueChange(object sender, BaseVariable<TValue>.OnChangeEventArgs onChangeEventArgs)
|
|
{
|
|
SubBaseTriggerValueListeners();
|
|
if (m_Variable != null)
|
|
{
|
|
InternalOnValueChange?.Invoke(m_Variable, onChangeEventArgs);
|
|
}
|
|
InternalOnReferencedValueChange?.Invoke(this, onChangeEventArgs);
|
|
}
|
|
|
|
protected virtual void OnEnable()
|
|
{
|
|
#if UNITY_EDITOR
|
|
EditorApplication.playModeStateChanged += HandlePlayModeStateChange;
|
|
#endif
|
|
//
|
|
// Listen on the variable value changing.
|
|
//
|
|
if (m_Variable != null)
|
|
{
|
|
m_Variable.OnChange += HandleValueChange;
|
|
}
|
|
}
|
|
|
|
protected virtual void OnDisable()
|
|
{
|
|
#if UNITY_EDITOR
|
|
EditorApplication.playModeStateChanged -= HandlePlayModeStateChange;
|
|
#endif
|
|
//
|
|
// Stop listening on the variable value changing.
|
|
//
|
|
if (m_Variable != null)
|
|
{
|
|
m_Variable.OnChange -= HandleValueChange;
|
|
}
|
|
|
|
/*#if UNITY_EDITOR
|
|
if (m_TestRuntimeVariable != null)
|
|
{
|
|
RogueUtils.Utils.NiceDestroy(m_TestRuntimeVariable);
|
|
m_TestRuntimeVariable = null;
|
|
}
|
|
#endif*/
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
private void HandlePlayModeStateChange(PlayModeStateChange stateChange)
|
|
{
|
|
bool doDefaultVariable = false;
|
|
switch (stateChange)
|
|
{
|
|
case PlayModeStateChange.EnteredEditMode:
|
|
break;
|
|
case PlayModeStateChange.ExitingEditMode:
|
|
break;
|
|
case PlayModeStateChange.EnteredPlayMode:
|
|
break;
|
|
case PlayModeStateChange.ExitingPlayMode:
|
|
doDefaultVariable = m_DefaultOnExitPlayMode;
|
|
break;
|
|
}
|
|
|
|
if (doDefaultVariable)
|
|
{
|
|
var defaultVariable = DefaultVariable;
|
|
//Undo.RecordObject(this, $"{name}: Clearing list");
|
|
m_Variable = defaultVariable;
|
|
//
|
|
// Marking this dirty so Unity sees the value is its default value
|
|
//
|
|
EditorUtility.SetDirty(this);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
public override SubBaseVariable GetVariableUntyped()
|
|
{
|
|
return Variable;
|
|
}
|
|
|
|
public override void SetVariableUntyped(SubBaseVariable variable)
|
|
{
|
|
if (variable is TVariable theVariable)
|
|
{
|
|
Variable = theVariable;
|
|
}
|
|
}
|
|
|
|
public override T GetValue<T>()
|
|
{
|
|
var variable = Variable;
|
|
if (variable != null)
|
|
{
|
|
var value = variable.Value;
|
|
if (value is T theValue)
|
|
{
|
|
return theValue;
|
|
}
|
|
}
|
|
|
|
return default;
|
|
}
|
|
|
|
public override object GetValueUntyped()
|
|
{
|
|
var variable = Variable;
|
|
if (variable != null)
|
|
{
|
|
return variable.Value;
|
|
}
|
|
|
|
return default;
|
|
}
|
|
|
|
public override void SetValueUntyped(object value)
|
|
{
|
|
var variable = Variable;
|
|
if (variable != null)
|
|
{
|
|
if (value is TValue theValue)
|
|
{
|
|
variable.Value = theValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public override void TriggerVariableListeners()
|
|
{
|
|
InternalOnVariableChange?.Invoke(this, EventArgs.Empty);
|
|
base.SubBaseTriggerVariableListeners();
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "Odin")]
|
|
private void BaseHandleEditorVariableChange()
|
|
{
|
|
Variable = m_InspectorVariable;
|
|
}
|
|
|
|
//[FoldoutGroup("Debug", Order = 200)]
|
|
//[BoxGroup("Debug/Runtime")]
|
|
//[ShowInInspector]
|
|
//[ReadOnly]
|
|
private TVariable m_TestRuntimeVariable;
|
|
|
|
//[BoxGroup("Debug/Runtime")]
|
|
//[Button("Set to runtime variable instance")]
|
|
//[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "Odin")]
|
|
private void SetToRuntimeInstance()
|
|
{
|
|
if (m_TestRuntimeVariable == null)
|
|
{
|
|
m_TestRuntimeVariable = ScriptableObject.CreateInstance<TVariable>();
|
|
}
|
|
|
|
Variable = m_TestRuntimeVariable;
|
|
}
|
|
#endif
|
|
}
|
|
}
|