#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