< Summary

Information
Line coverage
100%
Covered lines: 116
Uncovered lines: 0
Coverable lines: 116
Total lines: 358
Line coverage: 100%
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

File(s)

./Packages/se.hertzole.scriptable-values/Runtime/Values/ScriptableValue.Generic.Bindings.cs

#LineLine coverage
 1#if SCRIPTABLE_VALUES_RUNTIME_BINDING && SCRIPTABLE_VALUES_UITOOLKIT
 2using System.Collections.Generic;
 3
 4namespace Hertzole.ScriptableValues
 5{
 6    partial class ScriptableValue<T>
 7    {
 8        /// <inheritdoc />
 9        protected override long GetViewHashCode()
 129610        {
 11            unchecked
 129612            {
 129613                EqualityComparer<T> comparer = EqualityComparer<T>.Default;
 14
 129615                long hash = 17;
 129616                hash = hash * 23 + base.GetViewHashCode();
 129617                hash = hash * 23 + comparer.GetHashCode(Value);
 129618                hash = hash * 23 + comparer.GetHashCode(PreviousValue);
 129619                hash = hash * 23 + comparer.GetHashCode(DefaultValue);
 129620                return hash;
 21            }
 129622        }
 23    }
 24}
 25#endif

./Packages/se.hertzole.scriptable-values/Runtime/Values/ScriptableValue.Generic.cs

#LineLine coverage
 1#nullable enable
 2
 3using System;
 4using Hertzole.ScriptableValues.Helpers;
 5using UnityEngine;
 6using UnityEngine.Events;
 7#if SCRIPTABLE_VALUES_PROPERTIES
 8using Unity.Properties;
 9#endif
 10
 11namespace Hertzole.ScriptableValues
 12{
 13    /// <summary>
 14    ///     A <see cref="ScriptableValue{T}" /> that holds a value of type <typeparamref name="T" />.
 15    /// </summary>
 16    /// <typeparam name="T">The type of the value.</typeparam>
 17#if ODIN_INSPECTOR
 18  [Sirenix.OdinInspector.DrawWithUnity]
 19#endif
 20    public abstract partial class ScriptableValue<T> : ScriptableValue
 21    {
 22        [SerializeField]
 23        [EditorTooltip("The current value. This can be changed at runtime.")]
 24#if SCRIPTABLE_VALUES_PROPERTIES
 25        [DontCreateProperty]
 26#endif
 1512327        internal T value = default!;
 28        [SerializeField]
 29        [EditorTooltip("The default value. This is used when the value is reset.")]
 30#if SCRIPTABLE_VALUES_PROPERTIES
 31        [DontCreateProperty]
 32#endif
 1512333        internal T defaultValue = default!;
 34        [SerializeField]
 35        [EditorTooltip("Called before the current value is set.")]
 36#if SCRIPTABLE_VALUES_PROPERTIES
 37        [DontCreateProperty]
 38#endif
 1512339        internal UnityEvent<T, T> onValueChanging = new UnityEvent<T, T>();
 40        [SerializeField]
 41        [EditorTooltip("Called after the current value is set.")]
 42#if SCRIPTABLE_VALUES_PROPERTIES
 43        [DontCreateProperty]
 44#endif
 1512345        internal UnityEvent<T, T> onValueChanged = new UnityEvent<T, T>();
 46
 47        private bool valueIsDefault;
 48
 1512349        private T previousValue = default!;
 50
 51        // This is mainly use for OnValidate weirdness.
 52        // We need to have another value that is the value right before it gets modified.
 1512353        private T temporaryValue = default!;
 54
 55        /// <summary>
 56        ///     The current value. This can be changed at runtime.
 57        /// </summary>
 58#if SCRIPTABLE_VALUES_PROPERTIES
 59        [CreateProperty]
 60#endif
 61        //TODO: Mark this as nullable once Unity fixes properties properly supporting nullable generics.
 62        public T Value
 63        {
 10457164            get { return value; }
 65            set
 1942566            {
 1942567                AddStackTrace(1);
 68
 1942569                SetValue(value, true);
 1926370            }
 71        }
 72        /// <summary>
 73        ///     The previous value before the current value was set.
 74        /// </summary>
 75#if SCRIPTABLE_VALUES_PROPERTIES
 76#if SCRIPTABLE_VALUES_PROPERTIES_SUPPORTS_READONLY
 77        [CreateProperty(ReadOnly = true)]
 78#else
 79        [CreateProperty]
 80#endif // SCRIPTABLE_VALUES_PROPERTIES_SUPPORTS_READONLY
 81#endif // SCRIPTABLE_VALUES_PROPERTIES
 82        //TODO: Mark this as nullable once Unity fixes properties properly supporting nullable generics.
 83        public T PreviousValue
 84        {
 19937785            get { return previousValue; }
 10566086            internal set { SetField(ref previousValue, value, previousValueChangingArgs, previousValueChangedArgs); }
 87        }
 88        /// <summary>
 89        ///     The default value. This is used when the value is reset.
 90        /// </summary>
 91#if SCRIPTABLE_VALUES_PROPERTIES
 92        [CreateProperty]
 93#endif
 94        public T DefaultValue
 95        {
 17139696            get { return defaultValue; }
 1439197            set { SetField(ref defaultValue, value, defaultValueChangingArgs, defaultValueChangedArgs); }
 98        }
 99
 100        /// <summary>
 101        ///     Called before the current value is set.
 102        /// </summary>
 103        public event ValueEventHandler<T>? OnValueChanging;
 104        /// <summary>
 105        ///     Called after the current value is set.
 106        /// </summary>
 107        public event ValueEventHandler<T>? OnValueChanged;
 108
 109        /// <summary>
 110        ///     Sets the current value to a new value.
 111        /// </summary>
 112        /// <param name="newValue">The new value that should be set.</param>
 113        /// <param name="notify">If true, the OnValueChanging/Changed events are invoked.</param>
 114        private void SetValue(T newValue, bool notify)
 21339115        {
 116            // If the game is playing, we don't want to set the value if it's read only.
 21339117            Guard.IsNotReadOnly(this, name);
 118
 119            // If the equality check is enabled, we don't want to set the value if it's the same as the current value.
 21177120            if (SetEqualityCheck && IsSameValue(newValue, value))
 4431121            {
 4431122                return;
 123            }
 124
 16746125            if (!OnBeforeSetValue(value, newValue))
 156126            {
 156127                return;
 128            }
 129
 16590130            PreviousValue = temporaryValue;
 131            // Invoke the OnValueChanging event if notify is true.
 16590132            if (notify)
 15492133            {
 15492134                onValueChanging.Invoke(PreviousValue, newValue);
 15492135                OnValueChanging?.Invoke(PreviousValue, newValue);
 15492136                NotifyPropertyChanging(valueChangingArgs);
 15492137            }
 138
 139            // Update the value.
 16590140            value = newValue;
 16590141            temporaryValue = newValue;
 142
 16590143            valueIsDefault = EqualityHelper.Equals(value, default);
 144
 16590145            OnAfterSetValue(PreviousValue, newValue);
 146
 147            // Invoke the OnValueChanged event if notify is true.
 16590148            if (notify)
 15492149            {
 15492150                onValueChanged.Invoke(PreviousValue, newValue);
 15492151                OnValueChanged?.Invoke(PreviousValue, Value);
 15492152                NotifyPropertyChanged(valueChangedArgs);
 15492153            }
 21177154        }
 155
 156        /// <summary>
 157        ///     Called before the value is set. This can be used to prevent the value from being set.
 158        /// </summary>
 159        /// <param name="oldValue">The current value.</param>
 160        /// <param name="newValue">The new value that is going to be set.</param>
 161        /// <returns><c>true</c> if the value can be set; otherwise, <c>false</c>.</returns>
 162        /// <remarks>
 163        ///     This is called before the <see cref="OnValueChanging" /> event. This is also called no matter what `noti
 164        ///     set as.
 165        /// </remarks>
 166        protected virtual bool OnBeforeSetValue(T oldValue, T newValue)
 16278167        {
 16278168            return true;
 16278169        }
 170
 171        /// <summary>
 172        ///     Called when the value is set. This can be used to do something when the value is set.
 173        /// </summary>
 174        /// <param name="oldValue">The old value that was set.</param>
 175        /// <param name="newValue">The new value that was set.</param>
 176        /// <remarks>
 177        ///     This is called before the <see cref="OnValueChanged" /> event. This is also called no matter what `notif
 178        ///     set as.
 179        /// </remarks>
 32556180        protected virtual void OnAfterSetValue(T oldValue, T newValue) { }
 181
 182        /// <summary>
 183        ///     Helper method to check if the new value is the same as the old value.
 184        /// </summary>
 185        /// <param name="newValue">Thew new value.</param>
 186        /// <param name="oldValue">The old value.</param>
 187        /// <returns><c>true</c> if the values are the same; otherwise, <c>false</c>.</returns>
 188        protected bool IsSameValue(T newValue, T oldValue)
 19959189        {
 190            // If the new value is the default value and the old value isn't, we do allow setting a new value.
 191            // This is because Unity objects can be destroyed, but this change is not communicated to the ScriptableValu
 192            // So if it previously existed but is now null and we want to set it to null, we should allow it.
 19959193            if (EqualityHelper.Equals(newValue, default) && !valueIsDefault)
 1404194            {
 1404195                return false;
 196            }
 197
 18555198            return EqualityHelper.Equals(oldValue, newValue);
 19959199        }
 200
 201        /// <summary>
 202        ///     Sets the current value without invoking the <see cref="OnValueChanging" /> and <see cref="OnValueChanged
 203        ///     events.
 204        /// </summary>
 205        /// <param name="newValue">The new value.</param>
 206        public void SetValueWithoutNotify(T newValue)
 1098207        {
 1098208            AddStackTrace();
 209
 1098210            SetValue(newValue, false);
 1098211        }
 212
 213        /// <inheritdoc />
 214        protected override void OnPreStart()
 14631215        {
 216            // If the value should be reset, and it isn't a read only value, we set the value to the default value.
 14631217            if (ResetValueOnStart && !IsReadOnly)
 14631218            {
 14631219                ResetValue();
 14631220            }
 221
 222            // Remove any subscribers that are left over from play mode.
 223            // Don't warn if there are any subscribers left over because we already do that in OnExitPlayMode.
 14631224            ClearSubscribers();
 14631225        }
 226
 227        /// <inheritdoc />
 228        protected override void OnDisabled()
 14469229        {
 14469230            WarnIfLeftOverSubscribers();
 14469231        }
 232
 233        /// <summary>
 234        ///     Resets the value to the default value.
 235        /// </summary>
 236        public void ResetValue()
 17847237        {
 17847238            value = DefaultValue;
 17847239            PreviousValue = DefaultValue;
 17847240            temporaryValue = DefaultValue;
 17847241            valueIsDefault = EqualityHelper.Equals(value, default);
 17847242        }
 243
 244        /// <summary>
 245        ///     Warns if there are any left-over subscribers to the events.
 246        /// </summary>
 247        /// <remarks>This will only be called in the Unity editor and builds with the DEBUG flag.</remarks>
 248        protected override void WarnIfLeftOverSubscribers()
 14475249        {
 14475250            base.WarnIfLeftOverSubscribers();
 14475251            EventHelper.WarnIfLeftOverSubscribers(OnValueChanging, nameof(OnValueChanging), this);
 14475252            EventHelper.WarnIfLeftOverSubscribers(OnValueChanged, nameof(OnValueChanged), this);
 14475253        }
 254
 255        /// <summary>
 256        ///     Removes any subscribers from the event.
 257        /// </summary>
 258        /// <param name="warnIfLeftOver">
 259        ///     If true, a warning will be printed in the console if there are any subscribers.
 260        ///     The warning will only be printed in the editor and debug builds.
 261        /// </param>
 262        public void ClearSubscribers(bool warnIfLeftOver = false)
 14637263        {
 264#if DEBUG
 14637265            if (warnIfLeftOver)
 6266            {
 6267                WarnIfLeftOverSubscribers();
 6268            }
 269#endif
 270
 14637271            OnValueChanging = null;
 14637272            OnValueChanged = null;
 14637273        }
 274
 275#if UNITY_INCLUDE_TESTS
 276        /// <summary>
 277        ///     A test only check to see if <see cref="OnValueChanging" /> has subscribers.
 278        /// </summary>
 279        internal bool ValueChangingHasSubscribers
 280        {
 5148281            get { return OnValueChanging != null; }
 282        }
 283        /// <summary>
 284        ///     A test only check to see if <see cref="OnValueChanged" /> has subscribers.
 285        /// </summary>
 286        internal bool ValueChangedHasSubscribers
 287        {
 5148288            get { return OnValueChanged != null; }
 289        }
 290#endif
 291
 292#if UNITY_EDITOR
 293        internal void CallOnValidate_TestOnly()
 804294        {
 804295            OnValidate();
 804296        }
 297
 298        protected virtual void OnValidate()
 1038299        {
 1038300            SetValueOnValidateInternal();
 1038301        }
 302
 303        private void SetValueOnValidateInternal()
 1038304        {
 1038305            bool equals = false;
 1038306            bool originalSetEqualityCheck = SetEqualityCheck;
 307            // Only do an equality check if we're supposed to and that determines if we can set the new value or not.
 1038308            if (SetEqualityCheck)
 636309            {
 636310                equals = EqualityHelper.Equals(PreviousValue, value);
 311                // We need to turn off the equality check in OnValidate to make sure the value is set and the events are
 636312                SetEqualityCheck = false;
 636313            }
 314
 315            // If we can set the value, set it.
 1038316            if (!equals)
 816317            {
 816318                SetValue(value, true);
 816319            }
 320
 321            // Restore the original value.
 1038322            SetEqualityCheck = originalSetEqualityCheck;
 1038323        }
 324#endif
 325
 326        #region Obsolete
 327#if UNITY_EDITOR
 328        [Obsolete("Use 'Hertzole.ScriptableValues.ValueEventHandler<T>' instead. This will be removed in build.", true)]
 329        public delegate void OldNewValue<in TValue>(TValue previousValue, TValue newValue);
 330#endif
 331        #endregion
 332    }
 333}