| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 | 
							- // Animancer // Copyright 2018-2024 Kybernetik //
 
- #if UNITY_EDITOR
 
- using System.Collections;
 
- using System.Collections.Generic;
 
- using UnityEditor;
 
- using UnityEngine;
 
- namespace Animancer.Editor
 
- {
 
-     /// <summary>[Editor-Only]
 
-     /// A system which gathers information about <see cref="SerializeReference"/> fields to detect when multiple fields
 
-     /// are referencing the same object.
 
-     /// </summary>
 
-     /// https://kybernetik.com.au/animancer/api/Animancer.Editor/SharedReferenceCache
 
-     public class SharedReferenceCache :
 
-         IEnumerable<KeyValuePair<object, List<SharedReferenceCache.Field>>>
 
-     {
 
-         /************************************************************************************************************************/
 
-         #region Static Caching
 
-         /************************************************************************************************************************/
 
-         private static readonly Dictionary<SerializedObject, SharedReferenceCache>
 
-             SerializedObjectToCache = new();
 
-         /// <summary>Returns a cached <see cref="SharedReferenceCache"/> for the `serializedObject`.</summary>
 
-         public static SharedReferenceCache Get(SerializedObject serializedObject)
 
-         {
 
-             CheckFlush(serializedObject);
 
-             if (!SerializedObjectToCache.TryGetValue(serializedObject, out var cache))
 
-                 SerializedObjectToCache.Add(serializedObject, cache = new(serializedObject));
 
-             return cache;
 
-         }
 
-         /************************************************************************************************************************/
 
-         private static readonly HashSet<SerializedObject>
 
-             NotRecentlyUsed = new();
 
-         private const double
 
-             FlushInterval = 5;
 
-         private static double
 
-             _LastFlushTime;
 
-         /// <summary>Discards any caches not used during the last <see cref="FlushInterval"/> when it elapses.</summary>
 
-         private static void CheckFlush(SerializedObject serializedObject)
 
-         {
 
-             var currentTime = EditorApplication.timeSinceStartup;
 
-             if (currentTime >= _LastFlushTime + FlushInterval)
 
-             {
 
-                 _LastFlushTime = currentTime;
 
-                 foreach (var unused in NotRecentlyUsed)
 
-                     SerializedObjectToCache.Remove(unused);
 
-                 NotRecentlyUsed.Clear();
 
-                 NotRecentlyUsed.UnionWith(SerializedObjectToCache.Keys);
 
-             }
 
-             NotRecentlyUsed.Remove(serializedObject);
 
-         }
 
-         /************************************************************************************************************************/
 
-         /// <summary>The number of editor updates that have occurred since startup.</summary>
 
-         public static ulong FrameCount { get; private set; }
 
-         static SharedReferenceCache()
 
-         {
 
-             EditorApplication.update += () => FrameCount++;
 
-         }
 
-         /************************************************************************************************************************/
 
-         #endregion
 
-         /************************************************************************************************************************/
 
-         /// <summary>Information about a field.</summary>
 
-         public struct Field
 
-         {
 
-             /************************************************************************************************************************/
 
-             /// <summary>The <see cref="Serialization.GetFriendlyPath"/> of the field.</summary>
 
-             public string path;
 
-             /// <summary>The area where the field was last drawn.</summary>
 
-             public Rect area;
 
-             /************************************************************************************************************************/
 
-             /// <summary>Creates a new <see cref="Field"/>.</summary>
 
-             public Field(string path)
 
-             {
 
-                 this.path = path;
 
-                 area = default;
 
-             }
 
-             /************************************************************************************************************************/
 
-         }
 
-         /************************************************************************************************************************/
 
-         private readonly SerializedObject
 
-             SerializedObject;
 
-         private readonly Dictionary<object, List<Field>>
 
-             ObjectToReferences = new();
 
-         private ulong
 
-             _LastGatherFrameCount;
 
-         /************************************************************************************************************************/
 
-         /// <summary>Creates a new <see cref="SharedReferenceCache"/>.</summary>
 
-         public SharedReferenceCache(SerializedObject serializedObject)
 
-         {
 
-             SerializedObject = serializedObject;
 
-         }
 
-         /************************************************************************************************************************/
 
-         /// <summary>Should <see cref="GatherReferences"/> be called?</summary>
 
-         public bool ShouldGather
 
-             => _LastGatherFrameCount != FrameCount;
 
-         /// <summary>Updates the cached reference info.</summary>
 
-         public void GatherReferences()
 
-         {
 
-             _LastGatherFrameCount = FrameCount;
 
-             ObjectToReferences.Clear();
 
-             var property = SerializedObject.GetIterator();
 
-             while (property.Next(true))
 
-             {
 
-                 if (property.propertyType != SerializedPropertyType.ManagedReference)
 
-                     continue;
 
-                 var reference = property.managedReferenceValue;
 
-                 if (reference == null)
 
-                     continue;
 
-                 if (!ObjectToReferences.TryGetValue(reference, out var paths))
 
-                     ObjectToReferences.Add(reference, paths = new());
 
-                 paths.Add(new(property.GetFriendlyPath()));
 
-             }
 
-         }
 
-         /************************************************************************************************************************/
 
-         /// <summary>Tries to get the info about all fields containing the `reference`.</summary>
 
-         public bool TryGetInfo(object reference, out List<Field> references)
 
-         {
 
-             if (ShouldGather)
 
-                 GatherReferences();
 
-             return ObjectToReferences.TryGetValue(reference, out references);
 
-         }
 
-         /************************************************************************************************************************/
 
-         /// <summary>Returns an enumerator for all references and their info.</summary>
 
-         public Dictionary<object, List<Field>>.Enumerator GetEnumerator()
 
-         {
 
-             if (ShouldGather)
 
-                 GatherReferences();
 
-             return ObjectToReferences.GetEnumerator();
 
-         }
 
-         /// <summary>Returns an enumerator for all references and their info.</summary>
 
-         IEnumerator<KeyValuePair<object, List<Field>>> IEnumerable<KeyValuePair<object, List<Field>>>.GetEnumerator()
 
-             => GetEnumerator();
 
-         /// <summary>Returns an enumerator for all references and their info.</summary>
 
-         IEnumerator IEnumerable.GetEnumerator()
 
-             => GetEnumerator();
 
-         /************************************************************************************************************************/
 
-     }
 
- }
 
- #endif
 
 
  |