// Animancer // Copyright 2018-2024 Kybernetik //
#if UNITY_EDITOR
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace Animancer.Editor
{
/// [Editor-Only]
/// A system which gathers information about fields to detect when multiple fields
/// are referencing the same object.
///
/// https://kybernetik.com.au/animancer/api/Animancer.Editor/SharedReferenceCache
public class SharedReferenceCache :
IEnumerable>>
{
/************************************************************************************************************************/
#region Static Caching
/************************************************************************************************************************/
private static readonly Dictionary
SerializedObjectToCache = new();
/// Returns a cached for the `serializedObject`.
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
NotRecentlyUsed = new();
private const double
FlushInterval = 5;
private static double
_LastFlushTime;
/// Discards any caches not used during the last when it elapses.
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);
}
/************************************************************************************************************************/
/// The number of editor updates that have occurred since startup.
public static ulong FrameCount { get; private set; }
static SharedReferenceCache()
{
EditorApplication.update += () => FrameCount++;
}
/************************************************************************************************************************/
#endregion
/************************************************************************************************************************/
/// Information about a field.
public struct Field
{
/************************************************************************************************************************/
/// The of the field.
public string path;
/// The area where the field was last drawn.
public Rect area;
/************************************************************************************************************************/
/// Creates a new .
public Field(string path)
{
this.path = path;
area = default;
}
/************************************************************************************************************************/
}
/************************************************************************************************************************/
private readonly SerializedObject
SerializedObject;
private readonly Dictionary