< Summary

Information
Class: Hertzole.ScriptableValues.ScriptableValueListener[TValue]
Assembly: Hertzole.ScriptableValues
File(s): ./Packages/se.hertzole.scriptable-values/Runtime/Listeners/Values/ScriptableValueListener.cs
Tag: 52_28197466029
Line coverage
94%
Covered lines: 99
Uncovered lines: 6
Coverable lines: 105
Total lines: 350
Line coverage: 94.2%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
ScriptableValueListener()0%110100%
SetListening(...)0%220100%
OnCurrentValueChanging(...)0%6.066088.24%
OnBeforeValueChangingInvoked(...)0%110100%
OnAfterValueChangingInvoked(...)0%110100%
OnCurrentValueChanged(...)0%6.066088.24%
OnBeforeValueChangedInvoked(...)0%110100%
OnAfterValueChangedInvoked(...)0%110100%
SetTargetValue(...)0%660100%
SetListeningToObject(...)0%220100%
ShouldInvoke(...)0%660100%

File(s)

./Packages/se.hertzole.scriptable-values/Runtime/Listeners/Values/ScriptableValueListener.cs

#LineLine coverage
 1#nullable enable
 2
 3using Hertzole.ScriptableValues.Helpers;
 4using UnityEngine;
 5using UnityEngine.Events;
 6
 7namespace Hertzole.ScriptableValues
 8{
 9    /// <summary>
 10    ///     When listeners should start listening.
 11    /// </summary>
 12    public enum StartListenEvents
 13    {
 14        /// <summary>Start listening in Awake.</summary>
 15        Awake = 0,
 16        /// <summary>Start listening in Start.</summary>
 17        Start = 1,
 18        /// <summary>Start listening in OnEnable.</summary>
 19        OnEnable = 2
 20    }
 21
 22    /// <summary>
 23    ///     When listeners should stop listening.
 24    /// </summary>
 25    public enum StopListenEvents
 26    {
 27        /// <summary>Stop listening in OnDestroy.</summary>
 28        OnDestroy = 0,
 29        /// <summary>Stop listening in OnDisable.</summary>
 30        OnDisable = 1
 31    }
 32
 33    /// <summary>
 34    ///     When listeners should invoke their events.
 35    /// </summary>
 36    public enum InvokeEvents
 37    {
 38        /// <summary>When any value changed.</summary>
 39        Any = 0,
 40        /// <summary>When the old value matches a specific value.</summary>
 41        FromValue = 1,
 42        /// <summary>When the new value matches a specific value.</summary>
 43        ToValue = 2,
 44        /// <summary>When the old value and new value matches a specific value.</summary>
 45        FromValueToValue = 3
 46    }
 47
 48    /// <summary>
 49    ///     How many parameters listeners should use when invoking their events.
 50    /// </summary>
 51    public enum InvokeParameters
 52    {
 53        /// <summary>Invoke with a single parameter.</summary>
 54        Single = 1,
 55        /// <summary>Invoke with multiple parameters.</summary>
 56        Multiple = 2,
 57        /// <summary>Invoke with both single and multiple parameters..</summary>
 58        Both = 3
 59    }
 60
 61    /// <summary>
 62    ///     Base class for a component that listens to <see cref="ScriptableValue{T}" />.
 63    /// </summary>
 64    /// <typeparam name="TValue">The type to listen for.</typeparam>
 65    public abstract class ScriptableValueListener<TValue> : ScriptableListenerBase
 66    {
 67        [SerializeField]
 68        [EditorTooltip("The value to listen to.")]
 646869        private ScriptableValue<TValue>? targetValue = null;
 70        [SerializeField]
 71        [EditorTooltip("When listeners should invoke their events.")]
 646872        private InvokeEvents invokeOn = InvokeEvents.Any;
 73        [SerializeField]
 74        [EditorTooltip("What the old value needs to be for the event to be invoked.")]
 646875        private TValue? fromValue = default;
 76        [SerializeField]
 77        [EditorTooltip("What the new value needs to be for the event to be invoked.")]
 646878        private TValue? toValue = default;
 79
 80        [SerializeField]
 81        [EditorTooltip("How many parameters listeners should use when invoking their events.")]
 646882        private InvokeParameters invokeParameters = InvokeParameters.Single;
 83        [SerializeField]
 84        [EditorTooltip("The event to invoke when the value is changing.")]
 646885        private UnityEvent<TValue> onValueChangingSingle = new UnityEvent<TValue>();
 86        [SerializeField]
 87        [EditorTooltip("The event to invoke when the value has changed.")]
 646888        private UnityEvent<TValue> onValueChangedSingle = new UnityEvent<TValue>();
 89        [SerializeField]
 90        [EditorTooltip("The event to invoke when the value is changing.")]
 646891        private UnityEvent<TValue, TValue> onValueChangingMultiple = new UnityEvent<TValue, TValue>();
 92        [SerializeField]
 93        [EditorTooltip("The event to invoke when the value has changed.")]
 646894        private UnityEvent<TValue, TValue> onValueChangedMultiple = new UnityEvent<TValue, TValue>();
 95
 96        /// <summary>
 97        ///     The value to listen to.
 98        /// </summary>
 99        public ScriptableValue<TValue>? TargetValue
 100        {
 1404101            get { return targetValue; }
 18468102            set { SetTargetValue(value); }
 103        }
 104        /// <summary>
 105        ///     When listeners should invoke their events.
 106        /// </summary>
 107        public InvokeEvents InvokeOn
 108        {
 14256109            get { return invokeOn; }
 14256110            set { invokeOn = value; }
 111        }
 112        /// <summary>
 113        ///     What the old value needs to be for the event to be invoked.
 114        /// </summary>
 115        public TValue? FromValue
 116        {
 0117            get { return fromValue; }
 14256118            set { fromValue = value; }
 119        }
 120        /// <summary>
 121        ///     What the new value needs to be for the event to be invoked.
 122        /// </summary>
 123        public TValue? ToValue
 124        {
 0125            get { return toValue; }
 14256126            set { toValue = value; }
 127        }
 128        /// <summary>
 129        ///     How many parameters listeners should use when invoking their events.
 130        /// </summary>
 131        public InvokeParameters InvokeParameters
 132        {
 14256133            get { return invokeParameters; }
 14256134            set { invokeParameters = value; }
 135        }
 136
 137        /// <summary>
 138        ///     The event to invoke when the value is changing.
 139        /// </summary>
 140        public UnityEvent<TValue> OnValueChangingSingle
 141        {
 9504142            get { return onValueChangingSingle; }
 143        }
 144        /// <summary>
 145        ///     The event to invoke when the value has changed.
 146        /// </summary>
 147        public UnityEvent<TValue> OnValueChangedSingle
 148        {
 9504149            get { return onValueChangedSingle; }
 150        }
 151        /// <summary>
 152        ///     The event to invoke when the value is changing.
 153        /// </summary>
 154        public UnityEvent<TValue, TValue> OnValueChangingMultiple
 155        {
 9504156            get { return onValueChangingMultiple; }
 157        }
 158        /// <summary>
 159        ///     The event to invoke when the value has changed.
 160        /// </summary>
 161        public UnityEvent<TValue, TValue> OnValueChangedMultiple
 162        {
 9504163            get { return onValueChangedMultiple; }
 164        }
 165
 166        /// <inheritdoc />
 167        protected sealed override void SetListening(bool listen)
 13248168        {
 13248169            base.SetListening(listen);
 170
 171            // If the target value is null, just stop here.
 13248172            if (targetValue == null)
 6156173            {
 6156174                return;
 175            }
 176
 177            // Subscribe or unsubscribe to the target value's events.
 7092178            SetListeningToObject(targetValue, listen);
 13248179        }
 180
 181        /// <summary>
 182        ///     Called when the target value is changing.
 183        /// </summary>
 184        /// <param name="oldValue">The old value.</param>
 185        /// <param name="newValue">The new value.</param>
 186        private void OnCurrentValueChanging(TValue oldValue, TValue newValue)
 4752187        {
 4752188            if (ShouldInvoke(invokeOn, oldValue, newValue, fromValue, toValue))
 4752189            {
 4752190                if (!OnBeforeValueChangingInvoked(oldValue, newValue))
 0191                {
 0192                    return;
 193                }
 194
 4752195                switch (invokeParameters)
 196                {
 197                    case InvokeParameters.Single:
 1584198                        onValueChangingSingle.Invoke(newValue);
 1584199                        break;
 200                    case InvokeParameters.Multiple:
 1584201                        onValueChangingMultiple.Invoke(oldValue, newValue);
 1584202                        break;
 203                    case InvokeParameters.Both:
 1584204                        onValueChangingSingle.Invoke(newValue);
 1584205                        onValueChangingMultiple.Invoke(oldValue, newValue);
 1584206                        break;
 207                }
 208
 4752209                OnAfterValueChangingInvoked(oldValue, newValue);
 4752210            }
 4752211        }
 212
 213        /// <summary>
 214        ///     Called before the value changing event.
 215        /// </summary>
 216        /// <param name="oldValue">The current value.</param>
 217        /// <param name="newValue">The new value being set.</param>
 218        /// <returns><c>true</c> if the event should be invoked; otherwise, <c>false</c>.</returns>
 219        protected virtual bool OnBeforeValueChangingInvoked(TValue oldValue, TValue newValue)
 4752220        {
 4752221            return true;
 4752222        }
 223
 224        /// <summary>
 225        ///     Called after the value changing event.
 226        /// </summary>
 227        /// <param name="oldValue">The previous value.</param>
 228        /// <param name="newValue">The new value that was set.</param>
 9504229        protected virtual void OnAfterValueChangingInvoked(TValue oldValue, TValue newValue) { }
 230
 231        /// <summary>
 232        ///     Called when the target value has changed.
 233        /// </summary>
 234        /// <param name="oldValue">The old value.</param>
 235        /// <param name="newValue">The new value.</param>
 236        private void OnCurrentValueChanged(TValue oldValue, TValue newValue)
 4752237        {
 4752238            if (ShouldInvoke(invokeOn, oldValue, newValue, fromValue, toValue))
 4752239            {
 4752240                if (!OnBeforeValueChangedInvoked(oldValue, newValue))
 0241                {
 0242                    return;
 243                }
 244
 4752245                switch (invokeParameters)
 246                {
 247                    case InvokeParameters.Single:
 1584248                        onValueChangedSingle.Invoke(newValue);
 1584249                        break;
 250                    case InvokeParameters.Multiple:
 1584251                        onValueChangedMultiple.Invoke(oldValue, newValue);
 1584252                        break;
 253                    case InvokeParameters.Both:
 1584254                        onValueChangedSingle.Invoke(newValue);
 1584255                        onValueChangedMultiple.Invoke(oldValue, newValue);
 1584256                        break;
 257                }
 258
 4752259                OnAfterValueChangedInvoked(oldValue, newValue);
 4752260            }
 4752261        }
 262
 263        /// <summary>
 264        ///     Called before the value changed event.
 265        /// </summary>
 266        /// <param name="oldValue">The current value.</param>
 267        /// <param name="newValue">The new value being set.</param>
 268        /// <returns><c>true</c> if the event should be invoked; otherwise, <c>false</c>.</returns>
 269        protected virtual bool OnBeforeValueChangedInvoked(TValue oldValue, TValue newValue)
 4752270        {
 4752271            return true;
 4752272        }
 273
 274        /// <summary>
 275        ///     Called after the value changed event.
 276        /// </summary>
 277        /// <param name="oldValue">The previous value.</param>
 278        /// <param name="newValue">The new value that was set.</param>
 9504279        protected virtual void OnAfterValueChangedInvoked(TValue oldValue, TValue newValue) { }
 280
 281        /// <summary>
 282        ///     Sets the target value.
 283        /// </summary>
 284        /// <param name="newValue"></param>
 285        private void SetTargetValue(ScriptableValue<TValue>? newValue)
 6156286        {
 287            // If it's the same value, just stop here.
 6156288            if (newValue == targetValue)
 156289            {
 156290                return;
 291            }
 292
 293            // If we're listening to the old value, unsubscribe from its events.
 6000294            if (targetValue != null && IsListening)
 156295            {
 156296                SetListeningToObject(targetValue, false);
 156297            }
 298
 6000299            targetValue = newValue;
 300
 301            // If we're listening to the new value, subscribe to its events.
 6000302            if (targetValue != null && IsListening)
 6000303            {
 6000304                SetListeningToObject(targetValue, true);
 6000305            }
 6156306        }
 307
 308        private void SetListeningToObject(ScriptableValue<TValue> target, bool listen)
 13248309        {
 13248310            Guard.IsNotNull(target, nameof(target));
 311
 13248312            if (listen)
 6624313            {
 6624314                target.OnValueChanging += OnCurrentValueChanging;
 6624315                target.OnValueChanged += OnCurrentValueChanged;
 6624316            }
 317            else
 6624318            {
 6624319                target.OnValueChanging -= OnCurrentValueChanging;
 6624320                target.OnValueChanged -= OnCurrentValueChanged;
 6624321            }
 13248322        }
 323
 324        /// <summary>
 325        ///     Determines if the event should be invoked.
 326        /// </summary>
 327        /// <param name="invokeOn"></param>
 328        /// <param name="previousValue"></param>
 329        /// <param name="newValue"></param>
 330        /// <param name="fromValue"></param>
 331        /// <param name="toValue"></param>
 332        /// <returns><c>true</c> if the event should be invoked; otherwise, <c>false</c>.</returns>
 333        private static bool ShouldInvoke(InvokeEvents invokeOn, TValue? previousValue, TValue? newValue, TValue? fromVal
 9504334        {
 9504335            switch (invokeOn)
 336            {
 337                case InvokeEvents.FromValue: // If the old value is the from value.
 2376338                    return EqualityHelper.Equals(previousValue, fromValue);
 339                case InvokeEvents.ToValue:
 2376340                    return EqualityHelper.Equals(newValue, toValue); // If the new value is the to value.
 341                case InvokeEvents.FromValueToValue:
 2376342                    return EqualityHelper.Equals(previousValue, fromValue) &&
 343                           EqualityHelper.Equals(newValue, toValue); // If the old value is the from value and the new v
 344                case InvokeEvents.Any:
 345                default: // If anything happened (includes any)
 2376346                    return true;
 347            }
 9504348        }
 349    }
 350}