// 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 static void TriggerEventHandler <TArgs>(this GraphReference reference, Func <EventHook, bool> predicate, TArgs args, Func <IGraphParentElement, bool> recurse, bool force) { Ensure.That(nameof(reference)).IsNotNull(reference); foreach (var element in reference.graph.elements) { if (element is IGraphEventHandler <TArgs> handler && (predicate?.Invoke(handler.GetHook(reference)) ?? true)) { if (force || handler.IsListening(reference)) { handler.Trigger(reference, args); } } if (element is IGraphParentElement parentElement && recurse(parentElement)) { reference.ChildReference(parentElement, false, 0)?.TriggerEventHandler(predicate, args, recurse, force); } } }