using System; using System.Linq; using System.Reflection; using Sirenix.OdinInspector; using UnityEngine; namespace VOID.Generic { [Serializable] [HideReferenceObjectPicker] public class MultiSourceWrapper where T : class { /// /// Returns value from given source: /// - From inline object /// - From selected ScriptableObject (that have field "value") /// public T value => _usageType switch { MultiSourceUsageType.None => null, MultiSourceUsageType.Inline => _value, MultiSourceUsageType.ScriptableObject => _valueFromScriptableObject, _ => throw new ArgumentOutOfRangeException() }; [SerializeField] [EnumToggleButtons] [OnValueChanged(nameof(OnUsageTypeChange))] [HideLabel] private MultiSourceUsageType _usageType; [SerializeField] [ShowIf(nameof(_usageType), MultiSourceUsageType.Inline)] [HideLabel] private T _value; [SerializeField] [ShowIf(nameof(_usageType), MultiSourceUsageType.ScriptableObject)] [OnValueChanged(nameof(OnScriptableObjectSelected))] [HideLabel] private ScriptableObject _scriptableObject; private T _valueFromScriptableObject; private void OnScriptableObjectSelected() { var field = _scriptableObject.GetType() .GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .FirstOrDefault(field => field.Name == "value" && field.FieldType == typeof(T)); _valueFromScriptableObject = field == null ? default : field.GetValue(_scriptableObject) as T; } private void OnUsageTypeChange() { switch (_usageType) { case MultiSourceUsageType.None: _value = null; _scriptableObject = null; _valueFromScriptableObject = null; break; case MultiSourceUsageType.Inline: _scriptableObject = null; _valueFromScriptableObject = null; break; case MultiSourceUsageType.ScriptableObject: _value = null; break; default: throw new ArgumentOutOfRangeException(); } } } }