using System; using System.Collections.Generic; using UnityEngine; namespace Unity.VisualScripting { public static class GraphInstances { private static readonly object @lock = new object(); private static readonly Dictionary> byGraph = new Dictionary>(); private static readonly Dictionary> byParent = new Dictionary>(); public static void Instantiate(GraphReference instance) { lock (@lock) { Ensure.That(nameof(instance)).IsNotNull(instance); instance.CreateGraphData(); instance.graph.Instantiate(instance); if (!byGraph.TryGetValue(instance.graph, out var instancesWithGraph)) { instancesWithGraph = new HashSet(); byGraph.Add(instance.graph, instancesWithGraph); } if (instancesWithGraph.Add(instance)) { // Debug.Log($"Added graph instance mapping:\n{instance.graph} => {instance}"); } else { Debug.LogWarning($"Attempting to add duplicate graph instance mapping:\n{instance.graph} => {instance}"); } if (!byParent.TryGetValue(instance.parent, out var instancesWithParent)) { instancesWithParent = new HashSet(); byParent.Add(instance.parent, instancesWithParent); } if (instancesWithParent.Add(instance)) { // Debug.Log($"Added parent instance mapping:\n{instance.parent.ToSafeString()} => {instance}"); } else { Debug.LogWarning($"Attempting to add duplicate parent instance mapping:\n{instance.parent.ToSafeString()} => {instance}"); } } } public static void Uninstantiate(GraphReference instance) { lock (@lock) { instance.graph.Uninstantiate(instance); if (!byGraph.TryGetValue(instance.graph, out var instancesWithGraph)) { throw new InvalidOperationException("Graph instance not found via graph."); } if (instancesWithGraph.Remove(instance)) { // Debug.Log($"Removed graph instance mapping:\n{instance.graph} => {instance}"); // Free the key references for GC collection if (instancesWithGraph.Count == 0) { byGraph.Remove(instance.graph); } } else { Debug.LogWarning($"Could not find graph instance mapping to remove:\n{instance.graph} => {instance}"); } if (!byParent.TryGetValue(instance.parent, out var instancesWithParent)) { throw new InvalidOperationException("Graph instance not found via parent."); } if (instancesWithParent.Remove(instance)) { // Debug.Log($"Removed parent instance mapping:\n{instance.parent.ToSafeString()} => {instance}"); // Free the key references for GC collection if (instancesWithParent.Count == 0) { byParent.Remove(instance.parent); } } else { Debug.LogWarning($"Could not find parent instance mapping to remove:\n{instance.parent.ToSafeString()} => {instance}"); } // It's important to only free the graph data after // dissociating the instance mapping, because the data // is used as part of the equality comparison for pointers instance.FreeGraphData(); } } public static HashSet OfPooled(IGraph graph) { Ensure.That(nameof(graph)).IsNotNull(graph); lock (@lock) { if (byGraph.TryGetValue(graph, out var instances)) { // Debug.Log($"Found {instances.Count} instances of {graph}\n{instances.ToLineSeparatedString()}"); return instances.ToHashSetPooled(); } else { // Debug.Log($"Found no instances of {graph}.\n"); return HashSetPool.New(); } } } public static HashSet ChildrenOfPooled(IGraphParent parent) { Ensure.That(nameof(parent)).IsNotNull(parent); lock (@lock) { if (byParent.TryGetValue(parent, out var instances)) { // Debug.Log($"Found {instances.Count} instances of {parent.ToSafeString()}\n{instances.ToLineSeparatedString()}"); return instances.ToHashSetPooled(); } else { // Debug.Log($"Found no instances of {parent.ToSafeString()}.\n"); return HashSetPool.New(); } } } } }