protected override void OnUpdate() { #if UNITY_EDITOR // Live edit if (EditorApplication.isPlaying && 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 (!m_ShouldTriggerEventJob) { m_ShouldTriggerEventJob = ctx.ContainsEventReceiver; } m_EventFieldDescriptions = ctx.EventFields; }); #if VS_DOTS_PHYSICS_EXISTS VisualScriptingPhysics.SetupCollisionTriggerData(EntityManager, FrameCount, ref m_TriggerData, m_Query, VisualScriptingPhysics.EventType.Trigger); VisualScriptingPhysics.SetupCollisionTriggerData(EntityManager, FrameCount, 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); if (!m_Contexts.TryGetValue(e, out var ctx)) { return; } // used for random seed ctx.LastSystemVersion = LastSystemVersion; ctx.ResetFrame(); #if VS_TRACING if (s_TracingEnabled && ctx.FrameTrace == null) { ctx.FrameTrace = new DotsFrameTrace(Allocator.Persistent); } #endif #if VS_DOTS_PHYSICS_EXISTS TriggerPhysicsEvents(e, ref m_TriggerData, VisualScriptingPhysics.TriggerEventId); TriggerPhysicsEvents(e, ref m_CollisionData, VisualScriptingPhysics.CollisionEventId); #endif }); // Retrieve events that are dispatched from code if (m_ShouldTriggerEventJob) { m_DispatchedEvents.AddRange( VisualScriptingEventUtility.GetEventsFromApi(m_EventSystem, m_EventFieldDescriptions)); } // run each graph while there's either: // - a graph reference whose output trigger has been activated // - a graph input trigger has been activated by another graph referencing it // - events dispatched var ocount = m_OutputTriggersPerEntityGraphActivated.Count(); var icount = m_InputTriggersPerEntityGraphActivated.Count(); int iteration = 0; bool secondOutputTriggersMap = true; var dispatchedEvents = new List <EventNodeData>(); while (iteration == 0 || iteration < 100 && (ocount > 0 || icount > 0 || m_DispatchedEvents.Count > 0)) { // LogIterationReason(); dispatchedEvents.Clear(); ocount = 0; Entities.With(m_Query).ForEach(e => { if (!m_Contexts.TryGetValue(e, out GraphInstance ctx)) { return; } var beingDestroyed = m_BeingDestroyedQueryMask.Matches(e); if (beingDestroyed) { destroyed.Add(e); } // swap two hash maps - one for the current iteration and one for the next one, clear and swap after each iteration. // for some reason var tmp = h1; h1 = h2; h2 = tmp; didn't work var events = ctx.GlobalToLocalEventData(m_DispatchedEvents).ToList(); for (var i = 0; i < events.Count; ++i) { bool eventsTriggered = false; var evt = events[i]; // TODO: move that out of the loop once we remove the evt parameter of ResumeFrame and process events/inputs/graphrefs right at once if (eventsTriggered) { // keep filling the same output map. events might trigger graph outputs ctx.ResumeFrame(e, Time, evt, secondOutputTriggersMap ? m_OutputTriggersPerEntityGraphActivated : m_OutputTriggersPerEntityGraphActivated2); } } // this call will remove used entries from the input map var resumeInputs = ctx.TriggerGraphInputs(e, m_InputTriggersPerEntityGraphActivated); // this one won't as we need to process them for each graph. use the output map previously filled by the first ResumeFrame call and maybe the subsequent ones in the event loop var triggerGraphReferences = ctx.TriggerGraphReferences(e, secondOutputTriggersMap ? m_OutputTriggersPerEntityGraphActivated : m_OutputTriggersPerEntityGraphActivated2); if (iteration == 0 || resumeInputs || triggerGraphReferences) { // fill the other output map. ctx.ResumeFrame(e, Time, default, secondOutputTriggersMap
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(); }
protected override void OnUpdate() { SceneWithBuildConfigurationGUIDs.ValidateBuildSettingsCache(); var sceneSystem = World.GetExistingSystem <SceneSystem>(); var buildConfigurationGUID = sceneSystem.BuildConfigurationGUID; // Add scene entities that haven't been encountered yet if (!m_AddScenes.IsEmptyIgnoreFilter) { //@TODO: Should use Entities.ForEach but we are missing // 1. Entities.ForEach support with execute always (ILPP compilation not taking effect on first domain reload) // 2. Entities.ForEach not supporting explicit queries using (var addScenes = m_AddScenes.ToEntityArray(Allocator.TempJob)) { var trackerStates = new NativeArray <AssetDependencyTrackerState>(addScenes.Length, Allocator.Temp); for (int i = 0; i != addScenes.Length; i++) { var sceneEntity = addScenes[i]; var scene = EntityManager.GetComponentData <SceneReference>(sceneEntity); var requestSceneLoaded = EntityManager.GetComponentData <RequestSceneLoaded>(sceneEntity); var guid = SceneWithBuildConfigurationGUIDs.EnsureExistsFor(scene.SceneGUID, buildConfigurationGUID, out var requireRefresh); var async = (requestSceneLoaded.LoadFlags & SceneLoadFlags.BlockOnImport) == 0; LogResolving(async ? "Adding Async" : "Adding Sync", guid); _AssetDependencyTracker.Add(guid, sceneEntity, async); if (requireRefresh) { _AssetDependencyTracker.RequestRefresh(); } trackerStates[i] = new AssetDependencyTrackerState { SceneAndBuildConfigGUID = guid }; } EntityManager.AddComponentData(m_AddScenes, trackerStates); trackerStates.Dispose(); } } // Remove scene entities that were added and should no longer be tracked if (!m_RemoveScenes.IsEmptyIgnoreFilter) { using (var removeEntities = m_RemoveScenes.ToEntityArray(Allocator.TempJob)) using (var removeGuids = m_RemoveScenes.ToComponentDataArray <AssetDependencyTrackerState>(Allocator.TempJob)) { for (int i = 0; i != removeEntities.Length; i++) { LogResolving("Removing", removeGuids[i].SceneAndBuildConfigGUID); _AssetDependencyTracker.Remove(removeGuids[i].SceneAndBuildConfigGUID, removeEntities[i]); } } EntityManager.RemoveComponent <AssetDependencyTrackerState>(m_RemoveScenes); } // Process any scenes that have completed their asset import var isDone = _AssetDependencyTracker.GetCompleted(_Changed); foreach (var change in _Changed) { var sceneEntity = change.UserKey; LogResolving($"Resolving: {change.Asset} -> {change.ArtifactID}"); if (!m_ValidSceneMask.Matches(sceneEntity)) { throw new InvalidOperationException("entity should have been removed from tracker already"); } // Unload any previous state var unloadFlags = SceneSystem.UnloadParameters.DestroySectionProxyEntities | SceneSystem.UnloadParameters.DontRemoveRequestSceneLoaded; sceneSystem.UnloadScene(sceneEntity, unloadFlags); // Resolve new state var scene = EntityManager.GetComponentData <SceneReference>(change.UserKey); var request = EntityManager.GetComponentData <RequestSceneLoaded>(change.UserKey); if (change.ArtifactID != default) { ResolveSceneSectionUtility.ResolveSceneSections(EntityManager, change.UserKey, scene.SceneGUID, request, change.ArtifactID); } else { Debug.LogError( $"Failed to import entity scene because the automatically generated SceneAndBuildConfigGUID asset was not present: '{AssetDatabaseCompatibility.GuidToPath(scene.SceneGUID)}' -> '{AssetDatabaseCompatibility.GuidToPath(change.Asset)}'"); } } if (!isDone) { EditorUpdateUtility.EditModeQueuePlayerLoopUpdate(); } }
public void Execute(int index) { Entity e = SimulationChunksFirstSegment[index]; int iter = 0; do { if (iter++ >= 1000000) { throw new NotImplementedException(); } var segment = Segments[e]; var items = Items[e]; // Debug.Log($"{e} {segment} {items.Length}"); for (int i = 0; i < items.Length; i++) { ref BeltItem item = ref items.ElementAt(i); // simple case, too far from belt end to care about a next segment if (item.Distance > Settings.BeltDistanceSubDiv) { item.Distance--; segment.DistanceToInsertAtStart++; Segments[e] = segment; break; } // no next segment, so BeltDistanceSubDiv is the min distance // continue to move the next item on the belt if (segment.Next == Entity.Null) { continue; } if (!HasBeltSegmentMask.Matches(segment.Next)) { if (HasBeltSplitterMask.Matches(segment.Next)) { var splitter = Splitters[segment.Next]; // no room in input if (splitter.Input.Type != ItemType.None) { continue; } if (item.Distance > 0) // still inserting { item.Distance--; segment.DistanceToInsertAtStart++; Segments[e] = segment; break; } // will be update this frame item.Distance = (ushort)(Settings.BeltDistanceSubDiv); splitter.Input = item; Splitters[segment.Next] = splitter; items.RemoveAt(i); // Debug.Log("MOVE TO SPLITTER"); i--; } continue; } // only move if the next segment has room var nextBeltSegment = Segments[segment.Next]; if (nextBeltSegment.DistanceToInsertAtStart == 0) { continue; } if (item.Distance > 0) // still inserting { item.Distance--; segment.DistanceToInsertAtStart++; Segments[e] = segment; } else if (InsertInSegment(ref Items, ref Segments, item, segment.Next)) { items.RemoveAt(i); i--; } break; } e = segment.Prev; } while (e != Entity.Null);