First Commit
This commit is contained in:
254
Assets/BaseVariable.cs
Normal file
254
Assets/BaseVariable.cs
Normal file
@@ -0,0 +1,254 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using Golems.Attributes;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace RogueUtils.Data
|
||||
{
|
||||
public abstract class BaseVariable<T> : SubBaseVariable, IValueMonitor<T>
|
||||
#if UNITY_EDITOR
|
||||
, ISerializationCallbackReceiver
|
||||
#endif
|
||||
{
|
||||
//
|
||||
// NOTE: you cannot have Editor only serialised fields in Generics, it will crash a build
|
||||
// see https://issuetracker.unity3d.com/issues/serialization-layout-error-thrown-in-build-when-using-generic-classes-with-fields-that-only-exist-in-the-editor
|
||||
//
|
||||
[Multiline] public string m_Description = "";
|
||||
|
||||
[SerializeField] protected T m_Value;
|
||||
|
||||
// DW: Lets re-implement this down the line
|
||||
/*#if UNITY_EDITOR
|
||||
[NonSerialized]
|
||||
[ShowInInspector]
|
||||
[OnValueChanged("BaseHandleEditorValueChange")]
|
||||
[LabelText("Value")]
|
||||
//
|
||||
// This is an inspector editable version of the value
|
||||
//
|
||||
protected T m_EditorValue;
|
||||
#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<OnChangeEventArgs> InternalOnChange;
|
||||
|
||||
public event EventHandler<OnChangeEventArgs> OnChange
|
||||
{
|
||||
add
|
||||
{
|
||||
InternalOnChange += value;
|
||||
}
|
||||
|
||||
remove
|
||||
{
|
||||
InternalOnChange -= value;
|
||||
}
|
||||
}
|
||||
|
||||
public class OnChangeEventArgs : EventArgs
|
||||
{
|
||||
public T OldValue { get; private set; }
|
||||
|
||||
public T NewValue { get; private set; }
|
||||
|
||||
public OnChangeEventArgs(T value)
|
||||
{
|
||||
OldValue = value;
|
||||
NewValue = value;
|
||||
}
|
||||
|
||||
public OnChangeEventArgs(T oldValue, T newValue)
|
||||
{
|
||||
OldValue = oldValue;
|
||||
NewValue = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual T DefaultValue
|
||||
{
|
||||
get => default;
|
||||
}
|
||||
|
||||
public virtual T Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Value;
|
||||
}
|
||||
set
|
||||
{
|
||||
T oldValue = m_Value;
|
||||
m_Value = value;
|
||||
/*#if UNITY_EDITOR
|
||||
m_EditorValue = m_Value;
|
||||
#endif*/
|
||||
BaseHandleValueChange();
|
||||
InternalOnChange?.Invoke(this, new OnChangeEventArgs(oldValue, m_Value));
|
||||
}
|
||||
}
|
||||
|
||||
[Button]
|
||||
public void ForceOnChange()
|
||||
{
|
||||
InternalOnChange?.Invoke(this, new OnChangeEventArgs(m_Value));
|
||||
}
|
||||
|
||||
public override TValue GetValue<TValue>()
|
||||
{
|
||||
var value = Value;
|
||||
if (value is TValue theValue)
|
||||
{
|
||||
return theValue;
|
||||
}
|
||||
return default;
|
||||
}
|
||||
|
||||
public override object GetValueUntyped()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
|
||||
public override void SetValueUntyped(object value)
|
||||
{
|
||||
if (value is T theValue)
|
||||
{
|
||||
Value = theValue;
|
||||
}
|
||||
}
|
||||
|
||||
public void MonitoredValueChanged(T value, T _)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
EditorApplication.playModeStateChanged += HandlePlayModeStateChange;
|
||||
#endif
|
||||
}
|
||||
|
||||
protected virtual void OnDisable()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
EditorApplication.playModeStateChanged -= HandlePlayModeStateChange;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void HandlePlayModeStateChange(PlayModeStateChange stateChange)
|
||||
{
|
||||
bool doDefaultValue = false;
|
||||
switch (stateChange)
|
||||
{
|
||||
case PlayModeStateChange.EnteredEditMode:
|
||||
break;
|
||||
case PlayModeStateChange.ExitingEditMode:
|
||||
break;
|
||||
case PlayModeStateChange.EnteredPlayMode:
|
||||
break;
|
||||
case PlayModeStateChange.ExitingPlayMode:
|
||||
doDefaultValue = m_DefaultOnExitPlayMode;
|
||||
break;
|
||||
}
|
||||
|
||||
if (doDefaultValue)
|
||||
{
|
||||
var defaultValue = DefaultValue;
|
||||
//Undo.RecordObject(this, $"{name}: Clearing list");
|
||||
m_Value = defaultValue;
|
||||
#if UNITY_EDITOR
|
||||
// m_EditorValue = m_Value;
|
||||
#endif
|
||||
//
|
||||
// Marking this dirty so Unity sees the value is its default value
|
||||
// JJA: Doing this means the user has to manually save otherwise the Dirty flag carries over to the next time
|
||||
// Play is hit, causing it to save with the value it has after entering play mode (ie the runtime, not default value).
|
||||
// Bottom line: There is no need to set this dirty, as play mode changes aren't saved and by changing it back to default on exit we already avoid any chance of a runtime value being saved later
|
||||
// EditorUtility.SetDirty(this);
|
||||
}
|
||||
|
||||
AdditionalHandlePlayModeStateChange(stateChange);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Do any additional changes needed when changing PlayMode.
|
||||
/// NOTE: any override must be surrounded by #if UNITY_EDITOR as it is Editor only.
|
||||
/// </summary>
|
||||
/// <param name="stateChange"></param>
|
||||
protected virtual void AdditionalHandlePlayModeStateChange(PlayModeStateChange stateChange)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "Odin")]
|
||||
private void BaseHandleEditorValueChange()
|
||||
{
|
||||
HandleEditorValueChange();
|
||||
//
|
||||
// Marking this dirty so Unity sees the value change
|
||||
//
|
||||
EditorUtility.SetDirty(this);
|
||||
}
|
||||
|
||||
protected virtual void HandleEditorValueChange()
|
||||
{
|
||||
//Value = m_EditorValue;
|
||||
}
|
||||
|
||||
// [BoxGroup("Debug/Listeners")]
|
||||
// [HideIf("@this.m_InspectorValueListeners == null || this.m_InspectorValueListeners.Count == 0")]
|
||||
// [Button("Log Listeners")]
|
||||
private void LogListListeners()
|
||||
{
|
||||
var listeners = InternalOnChange?.GetInvocationList();
|
||||
|
||||
if (listeners == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
foreach (var listener in listeners)
|
||||
{
|
||||
builder.AppendLine(string.Format("{0}: listener {1}", name, listener));
|
||||
}
|
||||
Debug.Log(builder.ToString());
|
||||
}
|
||||
#endif
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (m_Value == null)
|
||||
{
|
||||
return name + " (null)";
|
||||
}
|
||||
return name + " (" + m_Value.ToString() + ")";
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public void OnBeforeSerialize()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnAfterDeserialize()
|
||||
{
|
||||
//m_EditorValue = m_Value;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user