Search Unity

[WIKI] Prevent Reset() to nullify objects like Unity does

Discussion in 'Scripting' started by aybe, Mar 16, 2019.

  1. aybe

    aybe

    Joined:
    May 24, 2015
    Posts:
    104
    This is my attempt to mimic the behavior in Unity such that when you do reset in-house components such as MeshFilter, the mesh reference is kept, very handy when you wish to reset only a subset of your properties!

    Code (CSharp):
    1. #if UNITY_EDITOR
    2. using System;
    3. using System.Linq.Expressions;
    4. using System.Reflection;
    5. using JetBrains.Annotations;
    6. using UnityEditor;
    7. using Object = UnityEngine.Object;
    8.  
    9. namespace Z
    10. {
    11.     /// <summary>
    12.     ///     Stores objects references in registry.
    13.     /// </summary>
    14.     public static class EditorPreferences
    15.     {
    16.         private static void Load<TSource, TProperty>(
    17.             [NotNull] TSource source, [NotNull] string sourceKey, [CanBeNull] ref TProperty target, [NotNull] string targetKey)
    18.             where TSource : Object
    19.             where TProperty : Object
    20.         {
    21.             if (source == null)
    22.                 throw new ArgumentNullException(nameof(source));
    23.  
    24.             if (sourceKey == null)
    25.                 throw new ArgumentNullException(nameof(sourceKey));
    26.  
    27.             if (targetKey == null)
    28.                 throw new ArgumentNullException(nameof(targetKey));
    29.  
    30.             var sourceId = source.GetInstanceID();
    31.  
    32.             var key = $"{sourceKey}.{sourceId}.{targetKey}";
    33.  
    34.             if (!EditorPrefs.HasKey(key))
    35.                 return;
    36.  
    37.             var id = EditorPrefs.GetInt(key);
    38.  
    39.             var o = EditorUtility.InstanceIDToObject(id);
    40.             if (o == null)
    41.                 return;
    42.  
    43.             target = o as TProperty;
    44.         }
    45.  
    46.         public static void Load<TSource, TProperty>([NotNull] TSource source, [NotNull] Expression<Func<TSource, TProperty>> property)
    47.             where TSource : Object
    48.             where TProperty : Object
    49.         {
    50.             if (source == null)
    51.                 throw new ArgumentNullException(nameof(source));
    52.  
    53.             if (property == null)
    54.                 throw new ArgumentNullException(nameof(property));
    55.  
    56.             if (!(property.Body is MemberExpression memberExpression))
    57.                 throw new ArgumentNullException(nameof(memberExpression));
    58.  
    59.             var fieldInfo = memberExpression.Member as FieldInfo;
    60.             if (fieldInfo == null)
    61.                 throw new ArgumentNullException(nameof(fieldInfo));
    62.  
    63.             var sourceKey = source.GetType().Name;
    64.  
    65.             var targetKey = fieldInfo.Name;
    66.  
    67.             var target = default(TProperty);
    68.  
    69.             Load(source, sourceKey, ref target, targetKey);
    70.  
    71.             fieldInfo.SetValue(source, target);
    72.         }
    73.  
    74.         private static void Save<TSource, TProperty>(
    75.             [NotNull] TSource source, [NotNull] string sourceKey, [CanBeNull] TProperty target, [NotNull] string targetKey)
    76.             where TSource : Object
    77.             where TProperty : Object
    78.         {
    79.             if (source == null)
    80.                 throw new ArgumentNullException(nameof(source));
    81.  
    82.             if (sourceKey == null)
    83.                 throw new ArgumentNullException(nameof(sourceKey));
    84.  
    85.             if (target == null)
    86.                 return;
    87.  
    88.             if (targetKey == null)
    89.                 throw new ArgumentNullException(nameof(targetKey));
    90.  
    91.             var sourceId = source.GetInstanceID();
    92.             var targetId = target.GetInstanceID();
    93.  
    94.             EditorPrefs.SetInt($"{sourceKey}.{sourceId}.{targetKey}", targetId);
    95.         }
    96.  
    97.         public static void Save<TSource, TProperty>([NotNull] TSource source, [NotNull] Expression<Func<TSource, TProperty>> property)
    98.             where TSource : Object
    99.             where TProperty : Object
    100.         {
    101.             if (source == null)
    102.                 throw new ArgumentNullException(nameof(source));
    103.  
    104.             if (property == null)
    105.                 throw new ArgumentNullException(nameof(property));
    106.  
    107.             if (!(property.Body is MemberExpression memberExpression))
    108.                 throw new ArgumentNullException(nameof(memberExpression));
    109.  
    110.             var info = memberExpression.Member as FieldInfo;
    111.             if (info == null)
    112.                 throw new ArgumentNullException(nameof(info));
    113.  
    114.             var sourceKey = source.GetType().Name;
    115.  
    116.             var target = info.GetValue(source) as Object;
    117.             if (target == null)
    118.                 return;
    119.  
    120.             var targetKey = info.Name;
    121.  
    122.             Save(source, sourceKey, target, targetKey);
    123.         }
    124.     }
    125. }
    126. #endif
    Use it like this:

    Code (CSharp):
    1.     public ScrollRect ScrollView;
    2.  
    3.     private void OnValidate()
    4.     {
    5.         EditorPreferences.Save(this, s => s.ScrollView);
    6.     }
    7.  
    8.     private void Reset()
    9.     {
    10.         EditorPreferences.Load(this, s => s.ScrollView);
    11.     }
    12.  
    Now when you reset the ScrollView reference is kept, works rather well :).

    Sharing this with the community, improvements are welcome!