Initial Commit

This commit is contained in:
Sebastian Cabrera 2021-08-02 05:44:37 -04:00
parent 53eb92e9af
commit 270ab7d11f
15341 changed files with 700234 additions and 0 deletions

View file

@ -0,0 +1,162 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Unity.VisualScripting
{
public abstract class Graph : IGraph
{
protected Graph()
{
elements = new MergedGraphElementCollection();
}
public override string ToString()
{
return StringUtility.FallbackWhitespace(title, base.ToString());
}
public abstract IGraphData CreateData();
public virtual IGraphDebugData CreateDebugData()
{
return new GraphDebugData(this);
}
public virtual void Instantiate(GraphReference instance)
{
// Debug.Log($"Instantiating graph {instance}");
foreach (var element in elements)
{
element.Instantiate(instance);
}
}
public virtual void Uninstantiate(GraphReference instance)
{
// Debug.Log($"Uninstantiating graph {instance}");
foreach (var element in elements)
{
element.Uninstantiate(instance);
}
}
#region Elements
[SerializeAs(nameof(elements))]
private List<IGraphElement> _elements = new List<IGraphElement>();
[DoNotSerialize]
public MergedGraphElementCollection elements { get; }
#endregion
#region Metadata
[Serialize]
public string title { get; set; }
[Serialize]
[InspectorTextArea(minLines = 1, maxLines = 10)]
public string summary { get; set; }
#endregion
#region Canvas
[Serialize]
public Vector2 pan { get; set; }
[Serialize]
public float zoom { get; set; } = 1;
#endregion
#region Serialization
public IEnumerable<ISerializationDependency> deserializationDependencies => _elements.SelectMany(e => e.deserializationDependencies);
public virtual void OnBeforeSerialize()
{
_elements.Clear();
_elements.AddRange(elements);
}
public void OnAfterDeserialize()
{
Serialization.AwaitDependencies(this);
}
public virtual void OnAfterDependenciesDeserialized()
{
elements.Clear();
// _elements.OrderBy(e => e.dependencyOrder)
var sortedElements = ListPool<IGraphElement>.New();
foreach (var element in _elements)
{
sortedElements.Add(element);
}
sortedElements.Sort((a, b) => a.dependencyOrder.CompareTo(b.dependencyOrder));
foreach (var element in sortedElements)
{
try
{
if (!element.HandleDependencies())
{
continue;
}
elements.Add(element);
}
catch (Exception ex)
{
Debug.LogWarning($"Failed to add element to graph during deserialization: {element}\n{ex}");
}
}
ListPool<IGraphElement>.Free(sortedElements);
}
#endregion
#region Poutine
public IEnumerable<object> aotStubs => elements.SelectMany(element => element.aotStubs);
private bool prewarmed;
public void Prewarm()
{
if (prewarmed)
{
return;
}
foreach (var element in elements)
{
element.Prewarm();
}
prewarmed = true;
}
public virtual void Dispose()
{
foreach (var element in elements)
{
element.Dispose();
}
}
#endregion
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3af658b760ac04b8ea3f040f301bbc1d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,117 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Unity.VisualScripting
{
public class GraphData<TGraph> : IGraphData
where TGraph : class, IGraph
{
public GraphData(TGraph definition)
{
this.definition = definition;
}
protected TGraph definition { get; }
protected Dictionary<IGraphElementWithData, IGraphElementData> elementsData { get; } = new Dictionary<IGraphElementWithData, IGraphElementData>();
protected Dictionary<IGraphParentElement, IGraphData> childrenGraphsData { get; } = new Dictionary<IGraphParentElement, IGraphData>();
protected Dictionary<Guid, IGraphElementData> phantomElementsData { get; } = new Dictionary<Guid, IGraphElementData>();
protected Dictionary<Guid, IGraphData> phantomChildrenGraphsData { get; } = new Dictionary<Guid, IGraphData>();
public bool TryGetElementData(IGraphElementWithData element, out IGraphElementData data)
{
return elementsData.TryGetValue(element, out data);
}
public bool TryGetChildGraphData(IGraphParentElement element, out IGraphData data)
{
return childrenGraphsData.TryGetValue(element, out data);
}
public IGraphElementData CreateElementData(IGraphElementWithData element)
{
// Debug.Log($"Creating element data for {element}");
if (elementsData.ContainsKey(element))
{
throw new InvalidOperationException($"Graph data already contains element data for {element}.");
}
IGraphElementData elementData;
if (phantomElementsData.TryGetValue(element.guid, out elementData))
{
// Debug.Log($"Restoring phantom element data for {element}.");
phantomElementsData.Remove(element.guid);
}
else
{
elementData = element.CreateData();
}
elementsData.Add(element, elementData);
return elementData;
}
public void FreeElementData(IGraphElementWithData element)
{
// Debug.Log($"Freeing element data for {element}");
if (elementsData.TryGetValue(element, out var elementData))
{
elementsData.Remove(element);
phantomElementsData.Add(element.guid, elementData);
}
else
{
Debug.LogWarning($"Graph data does not contain element data to free for {element}.");
}
}
public IGraphData CreateChildGraphData(IGraphParentElement element)
{
// Debug.Log($"Creating child graph data for {element}");
if (childrenGraphsData.ContainsKey(element))
{
throw new InvalidOperationException($"Graph data already contains child graph data for {element}.");
}
IGraphData childGraphData;
if (phantomChildrenGraphsData.TryGetValue(element.guid, out childGraphData))
{
// Debug.Log($"Restoring phantom child graph data for {element}.");
phantomChildrenGraphsData.Remove(element.guid);
}
else
{
childGraphData = element.childGraph.CreateData();
}
childrenGraphsData.Add(element, childGraphData);
return childGraphData;
}
public void FreeChildGraphData(IGraphParentElement element)
{
// Debug.Log($"Freeing child graph data for {element}");
if (childrenGraphsData.TryGetValue(element, out var childGraphData))
{
childrenGraphsData.Remove(element);
phantomChildrenGraphsData.Add(element.guid, childGraphData);
}
else
{
Debug.LogWarning($"Graph data does not contain child graph data to free for {element}.");
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e82ba0da11a744d4aa13044f972bf8f0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,37 @@
using System.Collections.Generic;
namespace Unity.VisualScripting
{
public class GraphDebugData : IGraphDebugData
{
protected Dictionary<IGraphElementWithDebugData, IGraphElementDebugData> elementsData { get; } = new Dictionary<IGraphElementWithDebugData, IGraphElementDebugData>();
protected Dictionary<IGraphParentElement, IGraphDebugData> childrenGraphsData { get; } = new Dictionary<IGraphParentElement, IGraphDebugData>();
IEnumerable<IGraphElementDebugData> IGraphDebugData.elementsData => elementsData.Values;
public GraphDebugData(IGraph definition) { }
public IGraphElementDebugData GetOrCreateElementData(IGraphElementWithDebugData element)
{
if (!elementsData.TryGetValue(element, out var elementDebugData))
{
elementDebugData = element.CreateDebugData();
elementsData.Add(element, elementDebugData);
}
return elementDebugData;
}
public IGraphDebugData GetOrCreateChildGraphData(IGraphParentElement element)
{
if (!childrenGraphsData.TryGetValue(element, out var data))
{
data = new GraphDebugData(element.childGraph);
childrenGraphsData.Add(element, data);
}
return data;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4ac0e89f600ed4b6da74436eb5fc67f7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,177 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Unity.VisualScripting
{
public abstract class GraphElement<TGraph> : IGraphElement where TGraph : class, IGraph
{
[Serialize]
public Guid guid { get; set; } = Guid.NewGuid();
// To minimize the amount of implementation needed, and simplify inversion of control,
// we provide instantiation routines that fit most types of elements in the right order and
// we provide implemented defaults for interfaces that the element could implement.
// Normally, an element shouldn't have to override instantiate or uninstantiate directly.
public virtual void Instantiate(GraphReference instance)
{
// Create the data for this graph, non-recursively, that is
// required for the nest instantiation, so we do it first.
if (this is IGraphElementWithData withData)
{
instance.data.CreateElementData(withData);
}
// Nest instantiation is a recursive operation that will
// call Instantiate on descendant graphs and elements.
// Because event listening will descend graph data recursively,
// we need to create it before.
if (this is IGraphNesterElement nester && nester.nest.graph != null)
{
GraphInstances.Instantiate(instance.ChildReference(nester, true));
}
// StartListening is a recursive operation that will
// descend graphs recursively. It must be called after
// instantiation of all child graphs because it will require
// their data. The drawback with this approach is that it will be
// called at each step bubbling up, whereas it will only
// effectively trigger once we reach the top level.
// Traversal is currently O(n!) where n is the number of descendants,
// ideally it would be O(n) if only triggered from the root.
// => Listening has to be implemented by Bolt classes, because Graphs isn't aware of the event system
}
public virtual void Uninstantiate(GraphReference instance)
{
// See above comments, in reverse order.
if (this is IGraphNesterElement nester && nester.nest.graph != null)
{
GraphInstances.Uninstantiate(instance.ChildReference(nester, true));
}
if (this is IGraphElementWithData withData)
{
instance.data.FreeElementData(withData);
}
}
public virtual void BeforeAdd() { }
public virtual void AfterAdd()
{
var instances = GraphInstances.OfPooled(graph);
foreach (var instance in instances)
{
Instantiate(instance);
}
instances.Free();
}
public virtual void BeforeRemove()
{
var instances = GraphInstances.OfPooled(graph);
foreach (var instance in instances)
{
Uninstantiate(instance);
}
instances.Free();
Dispose();
}
public virtual void AfterRemove() { }
public virtual void Dispose() { }
protected void InstantiateNest()
{
var nester = (IGraphNesterElement)this;
if (graph == null)
{
return;
}
var instances = GraphInstances.OfPooled(graph);
foreach (var instance in instances)
{
GraphInstances.Instantiate(instance.ChildReference(nester, true));
}
instances.Free();
}
protected void UninstantiateNest()
{
var nester = (IGraphNesterElement)this;
var instances = GraphInstances.ChildrenOfPooled(nester);
foreach (var instance in instances)
{
GraphInstances.Uninstantiate(instance);
}
instances.Free();
}
#region Graph
[DoNotSerialize]
public virtual int dependencyOrder => 0;
public virtual bool HandleDependencies() => true;
[DoNotSerialize]
public TGraph graph { get; set; }
[DoNotSerialize]
IGraph IGraphElement.graph
{
get => graph;
set
{
Ensure.That(nameof(value)).IsOfType<TGraph>(value);
graph = (TGraph)value;
}
}
[DoNotSerialize]
IGraph IGraphItem.graph => graph;
#endregion
#region Poutine
public virtual IEnumerable<ISerializationDependency> deserializationDependencies => Enumerable.Empty<ISerializationDependency>();
public virtual IEnumerable<object> aotStubs => Enumerable.Empty<object>();
public virtual void Prewarm() { }
protected void CopyFrom(GraphElement<TGraph> source) { }
public override string ToString()
{
var sb = new StringBuilder();
sb.Append(GetType().Name);
sb.Append("#");
sb.Append(guid.ToString().Substring(0, 5));
sb.Append("...");
return sb.ToString();
}
#endregion
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: df291d15317bf4d94820d46ed5deea4c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,130 @@
using System;
namespace Unity.VisualScripting
{
public sealed class GraphElementCollection<TElement> : GuidCollection<TElement>, IGraphElementCollection<TElement>, IProxyableNotifyCollectionChanged<TElement>
where TElement : IGraphElement
{
public GraphElementCollection(IGraph graph) : base()
{
Ensure.That(nameof(graph)).IsNotNull(graph);
this.graph = graph;
}
public IGraph graph { get; }
public event Action<TElement> ItemAdded;
public event Action<TElement> ItemRemoved;
public event Action CollectionChanged;
public bool ProxyCollectionChange { get; set; }
public void BeforeAdd(TElement element)
{
if (element.graph != null)
{
if (element.graph == graph)
{
throw new InvalidOperationException("Graph elements cannot be added multiple time into the same graph.");
}
else
{
throw new InvalidOperationException("Graph elements cannot be shared across graphs.");
}
}
element.graph = graph;
element.BeforeAdd();
}
public void AfterAdd(TElement element)
{
element.AfterAdd();
ItemAdded?.Invoke(element);
CollectionChanged?.Invoke();
}
public void BeforeRemove(TElement element)
{
element.BeforeRemove();
}
public void AfterRemove(TElement element)
{
element.graph = null;
element.AfterRemove();
ItemRemoved?.Invoke(element);
CollectionChanged?.Invoke();
}
protected override void InsertItem(int index, TElement element)
{
Ensure.That(nameof(element)).IsNotNull(element);
if (!ProxyCollectionChange)
{
BeforeAdd(element);
}
base.InsertItem(index, element);
if (!ProxyCollectionChange)
{
AfterAdd(element);
}
}
protected override void RemoveItem(int index)
{
var element = this[index];
if (!Contains(element))
{
throw new ArgumentOutOfRangeException(nameof(element));
}
if (!ProxyCollectionChange)
{
BeforeRemove(element);
}
base.RemoveItem(index);
if (!ProxyCollectionChange)
{
AfterRemove(element);
}
}
protected override void ClearItems()
{
// this.OrderByDescending(e => e.dependencyOrder).ToList()
var toRemove = ListPool<TElement>.New();
foreach (var element in this)
{
toRemove.Add(element);
}
toRemove.Sort((a, b) => b.dependencyOrder.CompareTo(a.dependencyOrder));
foreach (var element in toRemove)
{
Remove(element);
}
ListPool<TElement>.Free(toRemove);
}
protected override void SetItem(int index, TElement item)
{
throw new NotSupportedException();
}
public new NoAllocEnumerator<TElement> GetEnumerator()
{
return new NoAllocEnumerator<TElement>(this);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dd19e32f1cc4b4aa0be94290188834ef
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,152 @@
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<IGraph, HashSet<GraphReference>> byGraph = new Dictionary<IGraph, HashSet<GraphReference>>();
private static readonly Dictionary<IGraphParent, HashSet<GraphReference>> byParent = new Dictionary<IGraphParent, HashSet<GraphReference>>();
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<GraphReference>();
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<GraphReference>();
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<GraphReference> 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<GraphReference>.New();
}
}
}
public static HashSet<GraphReference> 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<GraphReference>.New();
}
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2779fdac2027441508654540bc9b17dc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,199 @@
using System;
using System.Collections.Generic;
namespace Unity.VisualScripting
{
public sealed class GraphNest<TGraph, TMacro> : IGraphNest
where TGraph : class, IGraph, new()
where TMacro : Macro<TGraph>
{
[DoNotSerialize]
public IGraphNester nester { get; set; }
[DoNotSerialize]
private GraphSource _source = GraphSource.Macro;
[DoNotSerialize]
private TMacro _macro;
[DoNotSerialize]
private TGraph _embed;
[Serialize]
public GraphSource source
{
get => _source;
set
{
if (value == source)
{
return;
}
BeforeGraphChange();
_source = value;
AfterGraphChange();
}
}
[Serialize]
public TMacro macro
{
get => _macro;
set
{
if (value == macro)
{
return;
}
BeforeGraphChange();
_macro = value;
AfterGraphChange();
}
}
[Serialize]
public TGraph embed
{
get => _embed;
set
{
if (value == embed)
{
return;
}
BeforeGraphChange();
_embed = value;
AfterGraphChange();
}
}
[DoNotSerialize]
public TGraph graph
{
get
{
switch (source)
{
case GraphSource.Embed:
return embed;
case GraphSource.Macro:
return macro?.graph;
default:
throw new UnexpectedEnumValueException<GraphSource>(source);
}
}
}
IMacro IGraphNest.macro
{
get => macro;
set => macro = (TMacro)value;
}
IGraph IGraphNest.embed
{
get => embed;
set => embed = (TGraph)value;
}
IGraph IGraphNest.graph => graph;
Type IGraphNest.graphType => typeof(TGraph);
Type IGraphNest.macroType => typeof(TMacro);
// TODO: Use these in the editor when appropriate to minimize change events
public void SwitchToEmbed(TGraph embed)
{
if (source == GraphSource.Embed && this.embed == embed)
{
return;
}
BeforeGraphChange();
_source = GraphSource.Embed;
_embed = embed;
_macro = null;
AfterGraphChange();
}
public void SwitchToMacro(TMacro macro)
{
if (source == GraphSource.Macro && this.macro == macro)
{
return;
}
BeforeGraphChange();
_source = GraphSource.Macro;
_embed = null;
_macro = macro;
AfterGraphChange();
}
public event Action beforeGraphChange;
public event Action afterGraphChange;
private void BeforeGraphChange()
{
if (graph != null)
{
nester.UninstantiateNest();
}
beforeGraphChange?.Invoke();
}
private void AfterGraphChange()
{
afterGraphChange?.Invoke();
if (graph != null)
{
nester.InstantiateNest();
}
}
#region Serialization
public IEnumerable<ISerializationDependency> deserializationDependencies
{
get
{
if (macro != null)
{
yield return macro;
}
}
}
#endregion
#region Poutine
[DoNotSerialize]
public IEnumerable<object> aotStubs => LinqUtility.Concat<object>(graph?.aotStubs);
[DoNotSerialize]
public bool hasBackgroundEmbed => source == GraphSource.Macro && embed != null;
#endregion
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a4dcc9606f76f4e0ca4401e047130678
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,717 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityObject = UnityEngine.Object;
namespace Unity.VisualScripting
{
public abstract class GraphPointer
{
#region Lifecycle
protected static bool IsValidRoot(IGraphRoot root)
{
return root?.childGraph != null && root as UnityObject != null;
}
protected static bool IsValidRoot(UnityObject rootObject)
{
return rootObject != null && (rootObject as IGraphRoot)?.childGraph != null;
}
internal GraphPointer() { }
protected void Initialize(IGraphRoot root)
{
if (!IsValidRoot(root))
{
throw new ArgumentException("Graph pointer root must be a valid Unity object with a non-null child graph.", nameof(root));
}
if (!(root is IMachine && root is MonoBehaviour || root is IMacro && root is ScriptableObject))
{
throw new ArgumentException("Graph pointer root must be either a machine or a macro.", nameof(root));
}
this.root = root;
parentStack.Add(root);
graphStack.Add(root.childGraph);
dataStack.Add(machine?.graphData);
debugDataStack.Add(fetchRootDebugDataBinding?.Invoke(root));
if (machine != null)
{
// Annoyingly, getting the gameObject property is an API call
// First, we'll try using our IMachine safe reference that is assigned in play mode on Awake
// If that fails, we'll try fetching it dynamically
if (machine.threadSafeGameObject != null)
{
gameObject = machine.threadSafeGameObject;
}
else if (UnityThread.allowsAPI)
{
gameObject = component.gameObject;
}
else
{
throw new GraphPointerException("Could not fetch graph pointer root game object.", this);
}
}
else
{
gameObject = null;
}
}
protected void Initialize(IGraphRoot root, IEnumerable<IGraphParentElement> parentElements, bool ensureValid)
{
Initialize(root);
Ensure.That(nameof(parentElements)).IsNotNull(parentElements);
foreach (var parentElement in parentElements)
{
if (!TryEnterParentElement(parentElement, out var error))
{
if (ensureValid)
{
throw new GraphPointerException(error, this);
}
break;
}
}
}
protected void Initialize(UnityObject rootObject, IEnumerable<Guid> parentElementGuids, bool ensureValid)
{
Initialize(rootObject as IGraphRoot);
Ensure.That(nameof(parentElementGuids)).IsNotNull(parentElementGuids);
foreach (var parentElementGuid in parentElementGuids)
{
if (!TryEnterParentElement(parentElementGuid, out var error))
{
if (ensureValid)
{
throw new GraphPointerException(error, this);
}
break;
}
}
}
#endregion
#region Conversion
public abstract GraphReference AsReference();
public virtual void CopyFrom(GraphPointer other)
{
root = other.root;
gameObject = other.gameObject;
parentStack.Clear();
parentElementStack.Clear();
graphStack.Clear();
dataStack.Clear();
debugDataStack.Clear();
foreach (var parent in other.parentStack)
{
parentStack.Add(parent);
}
foreach (var parentElement in other.parentElementStack)
{
parentElementStack.Add(parentElement);
}
foreach (var graph in other.graphStack)
{
graphStack.Add(graph);
}
foreach (var data in other.dataStack)
{
dataStack.Add(data);
}
foreach (var debugData in other.debugDataStack)
{
debugDataStack.Add(debugData);
}
}
#endregion
#region Stack
public IGraphRoot root { get; protected set; }
public UnityObject rootObject => root as UnityObject;
public IMachine machine => root as IMachine;
public IMacro macro => root as IMacro;
public MonoBehaviour component => root as MonoBehaviour;
public GameObject gameObject { get; private set; }
public GameObject self => gameObject;
public ScriptableObject scriptableObject => root as ScriptableObject;
public Scene? scene
{
get
{
if (gameObject == null)
{
return null;
}
var scene = gameObject.scene;
// We must allow to return unloaded scenes, because
// On Enable might try fetching scene variables for example
// See: https://support.ludiq.io/communities/5/topics/1864-/
if (!scene.IsValid() /* || !scene.isLoaded */)
{
return null;
}
return scene;
}
}
public UnityObject serializedObject
{
get
{
var depth = this.depth;
while (depth > 0)
{
var parent = parentStack[depth - 1];
if (parent.isSerializationRoot)
{
return parent.serializedObject;
}
depth--;
}
throw new GraphPointerException("Could not find serialized object.", this);
}
}
protected readonly List<IGraphParent> parentStack = new List<IGraphParent>();
protected readonly List<IGraphParentElement> parentElementStack = new List<IGraphParentElement>();
protected readonly List<IGraph> graphStack = new List<IGraph>();
protected readonly List<IGraphData> dataStack = new List<IGraphData>();
protected readonly List<IGraphDebugData> debugDataStack = new List<IGraphDebugData>();
public IEnumerable<Guid> parentElementGuids => parentElementStack.Select(parentElement => parentElement.guid);
#endregion
#region Utility
public int depth => parentStack.Count;
public bool isRoot => depth == 1;
public bool isChild => depth > 1;
public void EnsureDepthValid(int depth)
{
Ensure.That(nameof(depth)).IsGte(depth, 1);
if (depth > this.depth)
{
throw new GraphPointerException($"Trying to fetch a graph pointer level above depth: {depth} > {this.depth}", this);
}
}
public void EnsureChild()
{
if (!isChild)
{
throw new GraphPointerException("Graph pointer does not point to a child graph.", this);
}
}
public bool IsWithin<T>() where T : IGraphParent
{
return parent is T;
}
public void EnsureWithin<T>() where T : IGraphParent
{
if (!IsWithin<T>())
{
throw new GraphPointerException($"Graph pointer must be within a {typeof(T)} for this operation.", this);
}
}
public IGraphParent parent => parentStack[parentStack.Count - 1];
public T GetParent<T>() where T : IGraphParent
{
EnsureWithin<T>();
return (T)parent;
}
public IGraphParentElement parentElement
{
get
{
EnsureChild();
return parentElementStack[parentElementStack.Count - 1];
}
}
public IGraph rootGraph => graphStack[0];
public IGraph graph => graphStack[graphStack.Count - 1];
protected IGraphData _data
{
get => dataStack[dataStack.Count - 1];
set => dataStack[dataStack.Count - 1] = value;
}
public IGraphData data
{
get
{
EnsureDataAvailable();
return _data;
}
}
protected IGraphData _parentData => dataStack[dataStack.Count - 2];
public bool hasData => _data != null;
public void EnsureDataAvailable()
{
if (!hasData)
{
throw new GraphPointerException($"Graph data is not available.", this);
}
}
public T GetGraphData<T>() where T : IGraphData
{
var data = this.data;
if (data is T)
{
return (T)data;
}
throw new GraphPointerException($"Graph data type mismatch. Found {data.GetType()}, expected {typeof(T)}.", this);
}
public T GetElementData<T>(IGraphElementWithData element) where T : IGraphElementData
{
if (_data.TryGetElementData(element, out var elementData))
{
if (elementData is T)
{
return (T)elementData;
}
throw new GraphPointerException($"Graph element data type mismatch. Found {elementData.GetType()}, expected {typeof(T)}.", this);
}
throw new GraphPointerException($"Missing graph element data for {element}.", this);
}
public static Func<IGraphRoot, IGraphDebugData> fetchRootDebugDataBinding { get; set; }
public bool hasDebugData => _debugData != null;
public void EnsureDebugDataAvailable()
{
if (!hasDebugData)
{
throw new GraphPointerException($"Graph debug data is not available.", this);
}
}
protected IGraphDebugData _debugData
{
get => debugDataStack[debugDataStack.Count - 1];
set => debugDataStack[debugDataStack.Count - 1] = value;
}
public IGraphDebugData debugData
{
get
{
EnsureDebugDataAvailable();
return _debugData;
}
}
public T GetGraphDebugData<T>() where T : IGraphDebugData
{
var debugData = this.debugData;
if (debugData is T)
{
return (T)debugData;
}
throw new GraphPointerException($"Graph debug data type mismatch. Found {debugData.GetType()}, expected {typeof(T)}.", this);
}
public T GetElementDebugData<T>(IGraphElementWithDebugData element)
{
var elementDebugData = debugData.GetOrCreateElementData(element);
if (elementDebugData is T)
{
return (T)elementDebugData;
}
throw new GraphPointerException($"Graph element runtime debug data type mismatch. Found {elementDebugData.GetType()}, expected {typeof(T)}.", this);
}
#endregion
#region Traversal
protected bool TryEnterParentElement(Guid parentElementGuid, out string error, int? maxRecursionDepth = null)
{
if (!graph.elements.TryGetValue(parentElementGuid, out var element))
{
error = "Trying to enter a graph parent element with a GUID that is not within the current graph.";
return false;
}
if (!(element is IGraphParentElement))
{
error = "Provided element GUID does not point to a graph parent element.";
return false;
}
var parentElement = (IGraphParentElement)element;
return TryEnterParentElement(parentElement, out error, maxRecursionDepth);
}
protected bool TryEnterParentElement(IGraphParentElement parentElement, out string error, int? maxRecursionDepth = null, bool skipContainsCheck = false)
{
// The contains check is expensive because variant+merged collection checks
// If we already know for sure this error cannot happen, skipping it provides a significant optim
if (!skipContainsCheck && !graph.elements.Contains(parentElement))
{
error = "Trying to enter a graph parent element that is not within the current graph.";
return false;
}
var childGraph = parentElement.childGraph;
if (childGraph == null)
{
error = "Trying to enter a graph parent element without a child graph.";
return false;
}
if (Recursion.safeMode)
{
var recursionDepth = 0;
var _maxRecursionDepth = maxRecursionDepth ?? Recursion.defaultMaxDepth;
foreach (var parentGraph in graphStack)
{
if (parentGraph == childGraph)
{
recursionDepth++;
}
}
if (recursionDepth > _maxRecursionDepth)
{
error = $"Max recursion depth of {_maxRecursionDepth} has been exceeded. Are you nesting a graph within itself?\nIf not, consider increasing '{nameof(Recursion)}.{nameof(Recursion.defaultMaxDepth)}'.";
return false;
}
}
EnterValidParentElement(parentElement);
error = null;
return true;
}
protected void EnterParentElement(IGraphParentElement parentElement)
{
if (!TryEnterParentElement(parentElement, out var error))
{
throw new GraphPointerException(error, this);
}
}
protected void EnterParentElement(Guid parentElementGuid)
{
if (!TryEnterParentElement(parentElementGuid, out var error))
{
throw new GraphPointerException(error, this);
}
}
private void EnterValidParentElement(IGraphParentElement parentElement)
{
var childGraph = parentElement.childGraph;
parentStack.Add(parentElement);
parentElementStack.Add(parentElement);
graphStack.Add(childGraph);
IGraphData childGraphData = null;
_data?.TryGetChildGraphData(parentElement, out childGraphData);
dataStack.Add(childGraphData);
var childGraphDebugData = _debugData?.GetOrCreateChildGraphData(parentElement);
debugDataStack.Add(childGraphDebugData);
}
protected void ExitParentElement()
{
if (!isChild)
{
throw new GraphPointerException("Trying to exit the root graph.", this);
}
parentStack.RemoveAt(parentStack.Count - 1);
parentElementStack.RemoveAt(parentElementStack.Count - 1);
graphStack.RemoveAt(graphStack.Count - 1);
dataStack.RemoveAt(dataStack.Count - 1);
debugDataStack.RemoveAt(debugDataStack.Count - 1);
}
#endregion
#region Validation
public bool isValid
{
get
{
try
{
if (rootObject == null)
{
// Root object has been destroyed
return false;
}
if (rootGraph != root.childGraph)
{
// Root graph has changed
return false;
}
if (serializedObject == null)
{
// Serialized object has been destroyed
return false;
}
for (var depth = 1; depth < this.depth; depth++)
{
var parentElement = parentElementStack[depth - 1];
var parentGraph = graphStack[depth - 1];
var childGraph = graphStack[depth];
// Important to check by object and not by GUID here,
// because object stack integrity has to be guaranteed
// (GUID integrity is implied because they're immutable)
if (!parentGraph.elements.Contains(parentElement))
{
// Parent graph no longer contains the parent element
return false;
}
if (parentElement.childGraph != childGraph)
{
// Child graph has changed
return false;
}
}
return true;
}
catch (Exception ex)
{
Debug.LogWarning("Failed to check graph pointer validity: \n" + ex);
return false;
}
}
}
public void EnsureValid()
{
if (!isValid)
{
throw new GraphPointerException("Graph pointer is invalid.", this);
}
}
#endregion
#region Equality
public bool InstanceEquals(GraphPointer other)
{
if (ReferenceEquals(this, other))
{
return true;
}
if (!UnityObjectUtility.TrulyEqual(rootObject, other.rootObject))
{
return false;
}
if (!DefinitionEquals(other))
{
return false;
}
var depth = this.depth; // Micro optimization
for (int d = 0; d < depth; d++)
{
var data = dataStack[d];
var otherData = other.dataStack[d];
if (data != otherData)
{
return false;
}
}
return true;
}
public bool DefinitionEquals(GraphPointer other)
{
if (other == null)
{
return false;
}
if (rootGraph != other.rootGraph)
{
return false;
}
var depth = this.depth; // Micro optimization
if (depth != other.depth)
{
return false;
}
for (int d = 1; d < depth; d++)
{
var parentElement = parentElementStack[d - 1];
var otherParentElement = other.parentElementStack[d - 1];
if (parentElement != otherParentElement)
{
return false;
}
}
return true;
}
public int ComputeHashCode()
{
var hashCode = 17;
hashCode = hashCode * 23 + (rootObject.AsUnityNull()?.GetHashCode() ?? 0);
hashCode = hashCode * 23 + (rootGraph?.GetHashCode() ?? 0);
var depth = this.depth; // Micro optimization
for (int d = 1; d < depth; d++)
{
var parentElementGuid = parentElementStack[d - 1].guid;
hashCode = hashCode * 23 + parentElementGuid.GetHashCode();
}
return hashCode;
}
#endregion
#region Breadcrumbs
public override string ToString()
{
var sb = new StringBuilder();
sb.Append("[ ");
sb.Append(rootObject.ToSafeString());
for (var depth = 1; depth < this.depth; depth++)
{
sb.Append(" > ");
var parentElementIndex = depth - 1;
if (parentElementIndex >= parentElementStack.Count)
{
sb.Append("?");
break;
}
var parentElement = parentElementStack[parentElementIndex];
sb.Append(parentElement);
}
sb.Append(" ]");
return sb.ToString();
}
#endregion
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fb46e167769fd4b5e8f7c2ca3e0d431e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,14 @@
using System;
namespace Unity.VisualScripting
{
public sealed class GraphPointerException : Exception
{
public GraphPointer pointer { get; }
public GraphPointerException(string message, GraphPointer pointer) : base(message + "\n" + pointer)
{
this.pointer = pointer;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b217cb060732b439ab2575423ca7eb5d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,373 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityObject = UnityEngine.Object;
namespace Unity.VisualScripting
{
public sealed class GraphReference : GraphPointer
{
static GraphReference()
{
ReferenceCollector.onSceneUnloaded += FreeInvalidInterns;
}
#region Lifecycle
private GraphReference() { }
public static GraphReference New(IGraphRoot root, bool ensureValid)
{
if (!ensureValid && !IsValidRoot(root))
{
return null;
}
var reference = new GraphReference();
reference.Initialize(root);
reference.Hash();
return reference;
}
public static GraphReference New(IGraphRoot root, IEnumerable<IGraphParentElement> parentElements, bool ensureValid)
{
if (!ensureValid && !IsValidRoot(root))
{
return null;
}
var reference = new GraphReference();
reference.Initialize(root, parentElements, ensureValid);
reference.Hash();
return reference;
}
public static GraphReference New(UnityObject rootObject, IEnumerable<Guid> parentElementGuids, bool ensureValid)
{
if (!ensureValid && !IsValidRoot(rootObject))
{
return null;
}
var reference = new GraphReference();
reference.Initialize(rootObject, parentElementGuids, ensureValid);
reference.Hash();
return reference;
}
private static GraphReference New(GraphPointer model)
{
var reference = new GraphReference();
reference.CopyFrom(model);
return reference;
}
public override void CopyFrom(GraphPointer other)
{
base.CopyFrom(other);
if (other is GraphReference reference)
{
hashCode = reference.hashCode;
}
else
{
Hash();
}
}
public GraphReference Clone()
{
return New(this);
}
#endregion
#region Conversion
public override GraphReference AsReference()
{
return this;
}
public GraphStack ToStackPooled()
{
return GraphStack.New(this);
}
#endregion
#region Instantiation
public void CreateGraphData()
{
if (_data != null)
{
throw new GraphPointerException("Graph data already exists.", this);
}
if (isRoot)
{
if (machine != null)
{
// Debug.Log($"Creating root graph data for {this}");
_data = machine.graphData = graph.CreateData();
}
else
{
throw new GraphPointerException("Root graph data can only be created on machines.", this);
}
}
else
{
if (_parentData == null)
{
throw new GraphPointerException("Child graph data can only be created from parent graph data.", this);
}
_data = _parentData.CreateChildGraphData(parentElement);
}
}
public void FreeGraphData()
{
if (_data == null)
{
throw new GraphPointerException("Graph data does not exist.", this);
}
if (isRoot)
{
if (machine != null)
{
// Debug.Log($"Freeing root graph data for {this}");
_data = machine.graphData = null;
}
else
{
throw new GraphPointerException("Root graph data can only be freed on machines.", this);
}
}
else
{
if (_parentData == null)
{
throw new GraphPointerException("Child graph data can only be freed from parent graph data.", this);
}
_parentData.FreeChildGraphData(parentElement);
_data = null;
}
}
#endregion
#region Equality
[DoNotSerialize]
private int hashCode;
public override bool Equals(object obj)
{
if (!(obj is GraphReference other))
{
return false;
}
return InstanceEquals(other);
}
private void Hash()
{
hashCode = ComputeHashCode();
}
public override int GetHashCode()
{
return hashCode;
}
public static bool operator ==(GraphReference x, GraphReference y)
{
if (ReferenceEquals(x, y))
{
return true;
}
if (ReferenceEquals(x, null) || ReferenceEquals(y, null))
{
return false;
}
return x.Equals(y);
}
public static bool operator !=(GraphReference x, GraphReference y)
{
return !(x == y);
}
#endregion
#region Traversal
public GraphReference ParentReference(bool ensureValid)
{
if (isRoot)
{
if (ensureValid)
{
throw new GraphPointerException("Trying to get parent graph reference of a root.", this);
}
else
{
return null;
}
}
var pointer = Clone();
pointer.ExitParentElement();
pointer.Hash();
return pointer;
}
public GraphReference ChildReference(IGraphParentElement parentElement, bool ensureValid, int? maxRecursionDepth = null)
{
var pointer = Clone();
if (!pointer.TryEnterParentElement(parentElement, out var error, maxRecursionDepth))
{
if (ensureValid)
{
throw new GraphPointerException(error, this);
}
else
{
return null;
}
}
pointer.Hash();
return pointer;
}
#endregion
#region Validation
public GraphReference Revalidate(bool ensureValid)
{
try
{
// Important to recreate by GUIDs to avoid serialization ghosting
return New(rootObject, parentElementGuids, ensureValid);
}
catch (Exception ex)
{
if (ensureValid)
{
throw;
}
Debug.LogWarning("Failed to revalidate graph pointer: \n" + ex);
return null;
}
}
#endregion
#region Navigation
public IEnumerable<GraphReference> GetBreadcrumbs()
{
for (int depth = 0; depth < this.depth; depth++)
{
yield return New(root, parentElementStack.Take(depth), true);
}
}
#endregion
#region Interning
private static readonly Dictionary<int, List<GraphReference>> internPool = new Dictionary<int, List<GraphReference>>();
public static GraphReference Intern(GraphPointer pointer)
{
var hash = pointer.ComputeHashCode();
if (internPool.TryGetValue(hash, out var interns))
{
foreach (var intern in interns)
{
if (intern.InstanceEquals(pointer))
{
return intern;
}
}
var reference = New(pointer);
interns.Add(reference);
return reference;
}
else
{
var reference = New(pointer);
internPool.Add(reference.hashCode, new List<GraphReference>() { reference });
return reference;
}
}
public static void FreeInvalidInterns()
{
var invalidHashes = ListPool<int>.New();
foreach (var internsByHash in internPool)
{
var hash = internsByHash.Key;
var interns = internsByHash.Value;
var invalidInterns = ListPool<GraphReference>.New();
foreach (var intern in interns)
{
if (!intern.isValid)
{
invalidInterns.Add(intern);
}
}
foreach (var intern in invalidInterns)
{
interns.Remove(intern);
}
if (interns.Count == 0)
{
invalidHashes.Add(hash);
}
invalidInterns.Free();
}
foreach (var hash in invalidHashes)
{
internPool.Remove(hash);
}
invalidHashes.Free();
}
#endregion
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7f68b088e619c460d8aa786bc78bc3e9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,11 @@
using UnityEngine;
namespace Unity.VisualScripting
{
public enum GraphSource
{
Embed,
[InspectorName("Graph")]
Macro
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 73d6e074b5faa4ac1b86898dec2ca1c6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,112 @@
using System;
using System.Collections.Generic;
namespace Unity.VisualScripting
{
public sealed class GraphStack : GraphPointer, IPoolable, IDisposable
{
#region Lifecycle
private GraphStack() { }
private void InitializeNoAlloc(IGraphRoot root, List<IGraphParentElement> parentElements, bool ensureValid)
{
Initialize(root);
Ensure.That(nameof(parentElements)).IsNotNull(parentElements);
foreach (var parentElement in parentElements)
{
if (!TryEnterParentElement(parentElement, out var error))
{
if (ensureValid)
{
throw new GraphPointerException(error, this);
}
else
{
break;
}
}
}
}
internal static GraphStack New(IGraphRoot root, List<IGraphParentElement> parentElements)
{
var stack = GenericPool<GraphStack>.New(() => new GraphStack());
stack.InitializeNoAlloc(root, parentElements, true);
return stack;
}
internal static GraphStack New(GraphPointer model)
{
var stack = GenericPool<GraphStack>.New(() => new GraphStack());
stack.CopyFrom(model);
return stack;
}
public GraphStack Clone()
{
return New(this);
}
public void Dispose()
{
GenericPool<GraphStack>.Free(this);
}
void IPoolable.New()
{
}
void IPoolable.Free()
{
root = null;
parentStack.Clear();
parentElementStack.Clear();
graphStack.Clear();
dataStack.Clear();
debugDataStack.Clear();
}
#endregion
#region Conversion
public override GraphReference AsReference()
{
return ToReference();
}
public GraphReference ToReference()
{
return GraphReference.Intern(this);
}
#endregion
#region Traversal
public new void EnterParentElement(IGraphParentElement parentElement)
{
base.EnterParentElement(parentElement);
}
public bool TryEnterParentElement(IGraphParentElement parentElement)
{
return TryEnterParentElement(parentElement, out var error);
}
public bool TryEnterParentElementUnsafe(IGraphParentElement parentElement)
{
return TryEnterParentElement(parentElement, out var error, null, true);
}
public new void ExitParentElement()
{
base.ExitParentElement();
}
#endregion
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 33947f447eea3434e9c61e7975f2c9b5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,93 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Unity.VisualScripting
{
public static class GraphsExceptionUtility
{
// Note: Checking hasDebugData here instead of enableDebug,
// because we always want exceptions to register, even if
// background debug is disabled.
private const string handledKey = "Bolt.Core.Handled";
public static Exception GetException(this IGraphElementWithDebugData element, GraphPointer pointer)
{
if (!pointer.hasDebugData)
{
return null;
}
var debugData = pointer.GetElementDebugData<IGraphElementDebugData>(element);
return debugData.runtimeException;
}
public static void SetException(this IGraphElementWithDebugData element, GraphPointer pointer, Exception ex)
{
if (!pointer.hasDebugData)
{
return;
}
var debugData = pointer.GetElementDebugData<IGraphElementDebugData>(element);
debugData.runtimeException = ex;
}
public static void HandleException(this IGraphElementWithDebugData element, GraphPointer pointer, Exception ex)
{
Ensure.That(nameof(ex)).IsNotNull(ex);
if (pointer == null)
{
Debug.LogError("Caught exception with null graph pointer (flow was likely disposed):\n" + ex);
return;
}
var reference = pointer.AsReference();
if (!ex.HandledIn(reference))
{
element.SetException(pointer, ex);
}
while (reference.isChild)
{
var parentElement = reference.parentElement;
reference = reference.ParentReference(true);
if (parentElement is IGraphElementWithDebugData debuggableParentElement)
{
if (!ex.HandledIn(reference))
{
debuggableParentElement.SetException(reference, ex);
}
}
}
}
private static bool HandledIn(this Exception ex, GraphReference reference)
{
Ensure.That(nameof(ex)).IsNotNull(ex);
if (!ex.Data.Contains(handledKey))
{
ex.Data.Add(handledKey, new HashSet<GraphReference>());
}
var handled = (HashSet<GraphReference>)ex.Data[handledKey];
if (handled.Contains(reference))
{
return true;
}
else
{
handled.Add(reference);
return false;
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ba39e771494a542fb9f11fafe2479f54
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,26 @@
using System;
using UnityEngine;
namespace Unity.VisualScripting
{
public interface IGraph : IDisposable, IPrewarmable, IAotStubbable, ISerializationDepender
{
Vector2 pan { get; set; }
float zoom { get; set; }
MergedGraphElementCollection elements { get; }
string title { get; }
string summary { get; }
IGraphData CreateData();
IGraphDebugData CreateDebugData();
void Instantiate(GraphReference instance);
void Uninstantiate(GraphReference instance);
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e3ac3da4f4ae1479a860034ee83b9463
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,17 @@
namespace Unity.VisualScripting
{
public interface IGraphData
{
bool TryGetElementData(IGraphElementWithData element, out IGraphElementData data);
bool TryGetChildGraphData(IGraphParentElement element, out IGraphData data);
IGraphElementData CreateElementData(IGraphElementWithData element);
void FreeElementData(IGraphElementWithData element);
IGraphData CreateChildGraphData(IGraphParentElement element);
void FreeChildGraphData(IGraphParentElement element);
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8e1b7860a93164eeb84e96c8d6544df5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,13 @@
using System.Collections.Generic;
namespace Unity.VisualScripting
{
public interface IGraphDebugData
{
IGraphElementDebugData GetOrCreateElementData(IGraphElementWithDebugData element);
IGraphDebugData GetOrCreateChildGraphData(IGraphParentElement element);
IEnumerable<IGraphElementDebugData> elementsData { get; }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dee62c9ee6b8b4c4fb371dd99b538497
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
namespace Unity.VisualScripting
{
public interface IGraphElement : IGraphItem, INotifiedCollectionItem, IDisposable, IPrewarmable, IAotStubbable, IIdentifiable
{
new IGraph graph { get; set; }
bool HandleDependencies();
int dependencyOrder { get; }
new Guid guid { get; set; }
void Instantiate(GraphReference instance);
void Uninstantiate(GraphReference instance);
IEnumerable<ISerializationDependency> deserializationDependencies { get; }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cfe804b1243f445bdb36ab6c3360de35
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
using System;
namespace Unity.VisualScripting
{
public interface IGraphElementCollection<T> : IKeyedCollection<Guid, T>, INotifyCollectionChanged<T> where T : IGraphElement
{
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 37e7718ffdc7c4fdcbd2776305671c47
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,4 @@
namespace Unity.VisualScripting
{
public interface IGraphElementData { }
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: aac53a58d9e78493d916ada4ed9e309e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,10 @@
using System;
namespace Unity.VisualScripting
{
public interface IGraphElementDebugData
{
// Being lazy with the interfaces here to simplify things
Exception runtimeException { get; set; }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4dff94c93e9204acda46c024902f8949
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,7 @@
namespace Unity.VisualScripting
{
public interface IGraphElementWithData : IGraphElement
{
IGraphElementData CreateData();
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e8107ffb6540d4965a7e91dc321d9c3c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,7 @@
namespace Unity.VisualScripting
{
public interface IGraphElementWithDebugData : IGraphElement
{
IGraphElementDebugData CreateDebugData();
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 918e58f37ca08498c8d16db046eaf343
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,7 @@
namespace Unity.VisualScripting
{
public interface IGraphItem
{
IGraph graph { get; }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4da0cf276f0824701b16235437b01c34
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,19 @@
using System;
namespace Unity.VisualScripting
{
public interface IGraphNest : IAotStubbable
{
IGraphNester nester { get; set; }
GraphSource source { get; set; }
IGraph embed { get; set; }
IMacro macro { get; set; }
IGraph graph { get; }
Type graphType { get; }
Type macroType { get; }
bool hasBackgroundEmbed { get; }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 49fa2e46fd0be40b7939430e5ff3bf98
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,10 @@
namespace Unity.VisualScripting
{
public interface IGraphNester : IGraphParent
{
IGraphNest nest { get; }
void InstantiateNest();
void UninstantiateNest();
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b9cb6febeac1a471bac43cd4c509a764
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,4 @@
namespace Unity.VisualScripting
{
public interface IGraphNesterElement : IGraphParentElement, IGraphNester { }
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 870079fb53f614f1e97e352a303047d4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,15 @@
using UnityObject = UnityEngine.Object;
namespace Unity.VisualScripting
{
public interface IGraphParent
{
IGraph childGraph { get; }
bool isSerializationRoot { get; }
UnityObject serializedObject { get; }
IGraph DefaultGraph();
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ad05adb7ed2c342ac84cf9a4aafce6fb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,4 @@
namespace Unity.VisualScripting
{
public interface IGraphParentElement : IGraphElement, IGraphParent { }
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0c840ddd1fdb040759e04bfab84c6cab
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,7 @@
namespace Unity.VisualScripting
{
public interface IGraphRoot : IGraphParent
{
GraphPointer GetReference();
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 55b94feb6833e4cb4a7f7ed332598d2d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,27 @@
using System;
namespace Unity.VisualScripting
{
public sealed class MergedGraphElementCollection : MergedKeyedCollection<Guid, IGraphElement>, INotifyCollectionChanged<IGraphElement>
{
public event Action<IGraphElement> ItemAdded;
public event Action<IGraphElement> ItemRemoved;
public event Action CollectionChanged;
public override void Include<TSubItem>(IKeyedCollection<Guid, TSubItem> collection)
{
base.Include(collection);
var graphElementCollection = collection as IGraphElementCollection<TSubItem>;
if (graphElementCollection != null)
{
graphElementCollection.ItemAdded += (element) => ItemAdded?.Invoke(element);
graphElementCollection.ItemRemoved += (element) => ItemRemoved?.Invoke(element);
graphElementCollection.CollectionChanged += () => CollectionChanged?.Invoke();
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 12ce731cce6f947049d4c6d825a29c3d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: