#if GRAPH_DESIGNER /// --------------------------------------------- /// Behavior Designer /// Copyright (c) Opsive. All Rights Reserved. /// https://www.opsive.com /// --------------------------------------------- namespace Opsive.BehaviorDesigner.Runtime.Systems { using Opsive.BehaviorDesigner.Runtime.Components; using Opsive.BehaviorDesigner.Runtime.Core; using Opsive.BehaviorDesigner.Runtime.Groups; using Unity.Burst; using Unity.Collections; using Unity.Entities; using UnityEngine; /// /// System which checks for any tasks that should be reevaluated with conditional aborts. This system only marks the tasks, it does not do /// the actual reevaluation or interruption. /// [UpdateInGroup(typeof(BeforeTraversalSystemGroup), OrderFirst = true)] [UpdateBefore(typeof(ReevaluateTaskSystemGroup))] [DisableAutoCreation] public partial struct ReevaluateSystem : ISystem { private EntityQuery m_Query; /// /// Builds the query. /// /// THe current SystemState. private void OnCreate(ref SystemState state) { m_Query = SystemAPI.QueryBuilder().WithAllRW().WithAllRW().WithAll().WithAbsent().Build(); } /// /// Marks tasks that should be reevaluated with conditional aborts. /// /// The current SystemState. private void OnUpdate(ref SystemState state) { if (m_Query.IsEmptyIgnoreFilter) { return; } foreach (var (branchComponents, taskComponents, reevaluateTaskComponents, entity) in SystemAPI.Query, DynamicBuffer, DynamicBuffer>().WithAbsent().WithEntityAccess()) { var branchComponentsBuffer = branchComponents; var taskComponentsBuffer = taskComponents; var reevaluateTaskComponentsBuffer = reevaluateTaskComponents; BeforeTraversalCore.Reevaluate(state.EntityManager, entity, ref branchComponentsBuffer, ref taskComponentsBuffer, ref reevaluateTaskComponentsBuffer); } } } /// /// The tasks have been reevaluated. Compare the status to determine if an interrupt should occur. /// [UpdateInGroup(typeof(InterruptSystemGroup))] [UpdateBefore(typeof(InterruptSystem))] public partial struct ConditionalAbortsInvokerSystem : ISystem { private EntityQuery m_Query; /// /// Builds the query. /// /// THe current SystemState. private void OnCreate(ref SystemState state) { m_Query = SystemAPI.QueryBuilder().WithAllRW().WithAllRW().WithAllRW().WithAbsent().Build(); } /// /// Creates the jobs necessary for conditional aborts. /// /// The current SystemState. #if !UNITY_EDITOR [BurstCompile] #endif private void OnUpdate(ref SystemState state) { var ecb = new EntityCommandBuffer(Allocator.TempJob); state.Dependency = new ConditionalAbortsJob() { EntityCommandBuffer = ecb.AsParallelWriter() }.ScheduleParallel(m_Query, state.Dependency); // The jobs must be run immediately for the next systems. state.Dependency.Complete(); ecb.Playback(state.EntityManager); ecb.Dispose(); } /// /// Job which checks for any tasks that should be reevaluated with conditional aborts. This job only flags the tasks, it does not do /// the actual reevaluation or interruption. /// #if !UNITY_EDITOR [BurstCompile] #endif private partial struct ConditionalAbortsJob : IJobEntity { [Tooltip("CommandBuffer which sets the component data.")] public EntityCommandBuffer.ParallelWriter EntityCommandBuffer; /// /// Executes the job. /// /// The entity that is being acted upon. /// The index of the entity. /// An array of branch components. /// An array of task components. /// An array of reevaluate task components. #if !UNITY_EDITOR [BurstCompile] #endif public void Execute(Entity entity, [EntityIndexInQuery] int entityIndex, ref DynamicBuffer branchComponents, ref DynamicBuffer taskComponents, ref DynamicBuffer reevaluateTaskComponents) { BeforeTraversalCore.InvokeConditionalAborts(entity, entityIndex, ref branchComponents, ref taskComponents, ref reevaluateTaskComponents, EntityCommandBuffer); } } } /// /// Processes any interrupts. /// [UpdateInGroup(typeof(InterruptSystemGroup))] [UpdateAfter(typeof(ConditionalAbortsInvokerSystem))] [UpdateBefore(typeof(InterruptTaskSystemGroup))] public partial struct InterruptSystem : ISystem { private EntityQuery m_Query; /// /// Builds the query. /// /// THe current SystemState. private void OnCreate(ref SystemState state) { m_Query = SystemAPI.QueryBuilder().WithAllRW().WithAllRW().WithAll().Build(); } /// /// Creates the InterruptJob. /// /// The current SystemState. #if !UNITY_EDITOR [BurstCompile] #endif private void OnUpdate(ref SystemState state) { var ecb = new EntityCommandBuffer(Allocator.TempJob); state.Dependency = new InterruptJob() { EntityCommandBuffer = ecb.AsParallelWriter(), }.ScheduleParallel(m_Query, state.Dependency); // The job must run immediately for the next systems. state.Dependency.Complete(); ecb.Playback(state.EntityManager); ecb.Dispose(); } /// /// Triggers the interrupts. /// #if !UNITY_EDITOR [BurstCompile] #endif private partial struct InterruptJob : IJobEntity { [Tooltip("CommandBuffer which sets the component data.")] public EntityCommandBuffer.ParallelWriter EntityCommandBuffer; /// /// Executes the job. /// /// The entity that is being acted upon. /// The index of the entity. /// An array of branch components. /// An array of task components. #if !UNITY_EDITOR [BurstCompile] #endif public void Execute(Entity entity, [EntityIndexInQuery] int entityIndex, DynamicBuffer branchComponents, DynamicBuffer taskComponents) { BeforeTraversalCore.Interrupt(entity, entityIndex, branchComponents, taskComponents, EntityCommandBuffer); } } } /// /// Cleanup the interrupts after they have run. /// [UpdateInGroup(typeof(InterruptSystemGroup), OrderLast = true)] public partial struct InterruptCleanupSystem : ISystem { /// /// Executes the system. /// /// The current SystemState. #if !UNITY_EDITOR [BurstCompile] #endif private void OnUpdate(ref SystemState state) { foreach (var (branchComponents, entity) in SystemAPI.Query>().WithAll().WithEntityAccess()) { var branchComponentBuffer = branchComponents; BeforeTraversalCore.CleanupInterrupts(state.EntityManager, entity, ref branchComponentBuffer); } } } } #endif