public Execution TriggerGraphOutput(GraphInstance nestedContext, uint outputIndex)
        {
            Assert.IsNotNull(_parentContext.ParentGraphInstance);

            _parentContext.ParentGraphInstance.Trigger(_parentContext.CallingNode.Outputs.SelectPort(outputIndex));
            return(Execution.Interrupt);
        }
        internal GraphInstance CreateEntityContext(DynamicBuffer <ValueInput> inputs,
                                                   Entity e,
                                                   GraphDefinition graphDefinition)
        {
            Unity.Assertions.Assert.AreNotEqual(Entity.Null, e);
            GraphInstance ctx;
            var           graphContext = ctx = GraphInstance.Create(graphDefinition, EntityManager, inputs);

            ctx.ScriptingGraphRuntime = this;
            m_Contexts.Add(e, graphContext);
            foreach (var subgraphReference in graphDefinition.SubgraphReferences)
            {
                Value subgraphEntity = graphContext.ReadDataSlot(subgraphReference.SubgraphEntityDataIndex);
                CreateEntityContext(default,
        public Execution RunNestedGraph(GraphInstance graphInstance, ref GraphInstance.ActiveNodesState currentExecutionSavedState, GraphReference graphReference, Entity target, int triggerIndex)
        {
            // we're past matching the beingDestroyedQuery as ScriptingGraphInstance and all have already been removed
            if (!EntityManager.Exists(target) || !m_Contexts.TryGetValue(target, out GraphInstance otherContext))
            {
                Debug.LogError($"Running nested graph on destroyed entity: {target}, aborting");
                return(Execution.Done);
            }
            _parentContext.CallingNode         = graphReference;
            _parentContext.ParentGraphInstance = graphInstance;
            Assert.AreNotEqual(otherContext, graphInstance, "RunNested graph has been called with identical parent and child context");

            var savedUpdateState = otherContext.SaveActiveNodesState();

            if (currentExecutionSavedState.NodesToExecute == null)
            {
                currentExecutionSavedState.Init();// fetch from current node exec.SavedState
            }
            currentExecutionSavedState.MoveStateToNextFrame();
            otherContext.RestoreActiveNodesState(currentExecutionSavedState);

            if (triggerIndex != -1)
            {
                GraphDefinition.InputOutputTrigger nestedInputTrigger = otherContext.GetInputTrigger(triggerIndex);
                currentExecutionSavedState.AddExecutionThisFrame(nestedInputTrigger.NodeId);
            }

            bool nodesLeftToRun = true;

            while (nodesLeftToRun)
            {
                nodesLeftToRun = otherContext.ResumeFrame(target, Time, default);

                // copy the nested graph outputs to the reference node data output port. it used to be done when triggering a graph output,
                // but not all nested graphs have a output trigger, and calling graphs might just rely on data outputs.
                for (uint i = 0; i < _parentContext.CallingNode.DataOutputs.DataCount; i++)
                {
                    _parentContext.ParentGraphInstance.Write(_parentContext.CallingNode.DataOutputs.SelectPort(i), otherContext.ReadGraphOutputValue((int)i));
                }

                // add graphref to stack ?
                graphInstance.ResumeFrame(graphInstance.CurrentEntity, Time, default);
            }
            _parentContext = default;
            var stillRunning = currentExecutionSavedState.AnyNodeNextFrame;

            otherContext.RestoreActiveNodesState(savedUpdateState);

            return(stillRunning ? Execution.Running : Execution.Done);
        }
        protected override void OnUpdate()
        {
#if UNITY_EDITOR // Live edit
            if (m_Version != LastVersion)
            {
                m_Version = LastVersion;
                foreach (var contextsValue in m_Contexts.Values)
                {
                    contextsValue?.Dispose();
                }
                m_Contexts.Clear();
                EntityManager.RemoveComponent <ScriptingGraphInstance>(m_Query);
            }
#endif

            Entities.With(m_UninitializedQuery).ForEach((Entity e, ScriptingGraph g) =>
            {
                // Start
                var inputs = EntityManager.HasComponent <ValueInput>(e)
                    ? EntityManager.GetBuffer <ValueInput>(e)
                    : new DynamicBuffer <ValueInput>();
                GraphInstance ctx = CreateEntityContext(inputs, e, g.ScriptingGraphAsset.Definition);
#if VS_TRACING
                ctx.ScriptingGraphAssetID = g.ScriptingGraphAsset.GetInstanceID();
#endif
                EntityManager.AddComponentData(e, new ScriptingGraphInstance());
                EntityManager.AddComponentData(e, new ScriptingGraphInstanceAlive());
#if !UNITY_EDITOR // keep it for live edit
                EntityManager.RemoveComponent <ScriptingGraph>(e);
#endif
            });

#if VS_DOTS_PHYSICS_EXISTS
            VisualScriptingPhysics.SetupCollisionTriggerData(EntityManager, ref m_TriggerData, m_Query, VisualScriptingPhysics.EventType.Trigger);
            VisualScriptingPhysics.SetupCollisionTriggerData(EntityManager, ref m_CollisionData, m_Query, VisualScriptingPhysics.EventType.Collision);
#endif
            // A list: I assume the most common case is "the entity has not been destroyed"
            NativeList <Entity> destroyed = new NativeList <Entity>(Allocator.Temp);
            Entities.With(m_Query).ForEach((Entity e) =>
            {
                var beingDestroyed = m_BeingDestroyedQueryMask.Matches(e);

                GraphInstance ctx;

                //Get the context
                if (beingDestroyed)
                {
                    if (!m_Contexts.TryGetValue(e, out ctx))
                    {
                        return;
                    }
                    destroyed.Add(e);
                }
                else
                {
                    if (!m_Contexts.TryGetValue(e, out ctx))
                    {
                        // MBRIAU: Should this be an error?
                        return;
                    }
                }

                ctx.LastSystemVersion = LastSystemVersion;
                ctx.ResetFrame(); // TODO move at the end

#if VS_TRACING
                if (ctx.FrameTrace == null)
                {
                    ctx.FrameTrace = new DotsFrameTrace(Allocator.Persistent);
                }
#endif

                if (beingDestroyed)
                {
                    ctx.TriggerEntryPoints <OnDestroy>();
                    ctx.RunFrame(e, Time);

                    EntityManager.RemoveComponent <ScriptingGraphInstance>(e);
                    EntityManager.RemoveComponent <ScriptingGraph>(e);
                }
                else
                {
                    // Start
                    if (ctx.IsStarting)
                    {
                        ctx.TriggerEntryPoints <OnStart>();
                        ctx.IsStarting = false;
                    }

                    // Update
                    ctx.TriggerEntryPoints <OnUpdate>();
                    ctx.TriggerEntryPoints <OnKey>();

#if VS_DOTS_PHYSICS_EXISTS
                    TriggerPhysicsEvents(e, ref m_TriggerData, VisualScriptingPhysics.TriggerEventId);
                    TriggerPhysicsEvents(e, ref m_CollisionData, VisualScriptingPhysics.CollisionEventId);
#endif
                    // Actually execute all nodes active
                    ctx.RunFrame(e, Time);

                    m_DispatchedEvents.AddRange(ctx.DispatchedEvents);
                }
            });

            TriggerEvents(m_DispatchedEvents);

#if VS_TRACING
            foreach (var graphInstancePair in m_Contexts)
            {
                var graphInstance = graphInstancePair.Value;
                if (graphInstance?.FrameTrace != null)
                {
                    DotsFrameTrace.FlushFrameTrace(graphInstance.ScriptingGraphAssetID, UnityEngine.Time.frameCount,
                                                   graphInstance.CurrentEntity,
#if UNITY_EDITOR
                                                   EntityManager.GetName(graphInstance.CurrentEntity),
#else
                                                   e.Index.ToString(),
#endif
                                                   graphInstance.FrameTrace);
                    graphInstance.FrameTrace = null;
                }
            }
#endif
            for (var index = 0; index < destroyed.Length; index++)
            {
                var entity = destroyed[index];
                m_Contexts[entity].Dispose();
                m_Contexts.Remove(entity);
            }

            destroyed.Dispose();
        }