#if GRAPH_DESIGNER /// --------------------------------------------- /// Behavior Designer /// Copyright (c) Opsive. All Rights Reserved. /// https://www.opsive.com /// --------------------------------------------- namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions { using Opsive.BehaviorDesigner.Runtime.Components; using Opsive.BehaviorDesigner.Runtime.Utility; using Opsive.GraphDesigner.Runtime; using Unity.Entities; using Unity.Burst; using UnityEngine; using Unity.Collections; [NodeIcon("7c0aba0d8377aac48966d8e3f817a2a8", "90105f40f82a30e45b08d150c1928950")] [NodeDescription("Performs the actual interruption. This will immediately stop the specified tasks from running and will return success or failure depending on the value of interrupt success.")] public struct PerformInterruption : ILogicNode, ITaskComponentData, IAction { [Tooltip("The index of the node.")] [SerializeField] ushort m_Index; [Tooltip("The parent index of the node. ushort.MaxValue indicates no parent.")] [SerializeField] ushort m_ParentIndex; [Tooltip("The sibling index of the node. ushort.MaxValue indicates no sibling.")] [SerializeField] ushort m_SiblingIndex; [Tooltip("The task that should be interrupted.")] [SerializeField] ILogicNode[] m_InterruptTasks; [Tooltip("Should the interrupted task return success?")] [SerializeField] bool m_InterruptSuccess; public ushort Index { get => m_Index; set => m_Index = value; } public ushort ParentIndex { get => m_ParentIndex; set => m_ParentIndex = value; } public ushort SiblingIndex { get => m_SiblingIndex; set => m_SiblingIndex = value; } public ushort RuntimeIndex { get; set; } public ComponentType Tag { get => typeof(PerformInterruptionTag); } public System.Type SystemType { get => typeof(PerformInterruptionTaskSystem); } /// /// Adds the IBufferElementData to the entity. /// /// The world that the entity exists. /// The entity that the IBufferElementData should be assigned to. public void AddBufferElement(World world, Entity entity) { if (m_InterruptTasks == null || m_InterruptTasks.Length == 0) { UnityEngine.Debug.LogError("Error: At least one interrupt task must be specified."); return; } DynamicBuffer buffer; if (world.EntityManager.HasBuffer(entity)) { buffer = world.EntityManager.GetBuffer(entity); } else { buffer = world.EntityManager.AddBuffer(entity); } var indicies = new ushort[m_InterruptTasks.Length]; var nullTaskCount = 0; for (int i = 0; i < m_InterruptTasks.Length; ++i) { if (m_InterruptTasks[i] == null) { nullTaskCount++; continue; } indicies[i - nullTaskCount] = m_InterruptTasks[i].Index; } if (nullTaskCount > 0) { System.Array.Resize(ref indicies, indicies.Length - nullTaskCount); } var builder = new BlobBuilder(Allocator.Temp); ref var root = ref builder.ConstructRoot(); var indicesArray = builder.Allocate(ref root.Indicies, indicies.Length); for (int i = 0; i < indicies.Length; i++) { indicesArray[i] = indicies[i]; } var blobAsset = builder.CreateBlobAssetReference(Allocator.Persistent); builder.Dispose(); buffer.Add(new PerformInterruptionComponent() { Index = RuntimeIndex, InterruptIndicies = blobAsset, InterruptSuccess = m_InterruptSuccess }); var entityManager = world.EntityManager; ComponentUtility.AddInterruptComponents(entityManager, entity); } /// /// Clears the IBufferElementData from the entity. /// /// The world that the entity exists. /// The entity that the IBufferElementData should be cleared from. public void ClearBufferElement(World world, Entity entity) { DynamicBuffer buffer; if (world.EntityManager.HasBuffer(entity)) { buffer = world.EntityManager.GetBuffer(entity); buffer.Clear(); } } } /// /// The DOTS data structure for the PerformInterruption class. /// public struct PerformInterruptionComponent : IBufferElementData { [Tooltip("The index of the node.")] [SerializeField] public ushort Index; [Tooltip("The indicies of the tasks that should be interrupted.")] [SerializeField] public BlobAssetReference InterruptIndicies; [Tooltip("Should the interrupted tasks return success?")] [SerializeField] public bool InterruptSuccess; } /// /// A DOTS tag indicating when a PerformInterruption node is active. /// public struct PerformInterruptionTag : IComponentData, IEnableableComponent { } /// /// Runs the PerformInterruption logic. /// [DisableAutoCreation] public partial struct PerformInterruptionTaskSystem : ISystem { /// /// Updates the logic. /// /// The current state of the system. [BurstCompile] private void OnUpdate(ref SystemState state) { foreach (var (branchComponents, taskComponents, performInterruptionComponents, entity) in SystemAPI.Query, DynamicBuffer, DynamicBuffer>().WithAll().WithEntityAccess()) { for (int i = 0; i < performInterruptionComponents.Length; ++i) { var performInterruptionComponent = performInterruptionComponents[i]; var taskComponent = taskComponents[performInterruptionComponent.Index]; if (taskComponent.Status == TaskStatus.Queued) { taskComponent.Status = TaskStatus.Success; var taskComponentsBuffer = taskComponents; taskComponentsBuffer[taskComponent.Index] = taskComponent; var branchComponentsBuffer = branchComponents; for (int j = 0; j < performInterruptionComponent.InterruptIndicies.Value.Indicies.Length; ++j) { var interruptTaskComponent = taskComponents[performInterruptionComponent.InterruptIndicies.Value.Indicies[j]]; var interruptBranchComponent = branchComponents[interruptTaskComponent.BranchIndex]; interruptBranchComponent.InterruptType = performInterruptionComponent.InterruptSuccess ? InterruptType.ImmediateSuccess : InterruptType.ImmediateFailure; interruptBranchComponent.InterruptIndex = interruptTaskComponent.Index; branchComponentsBuffer[interruptTaskComponent.BranchIndex] = interruptBranchComponent; } state.EntityManager.SetComponentEnabled(entity, true); } } } } /// /// The task has been destroyed. /// /// The current state of the system. private void OnDestroy(ref SystemState state) { foreach (var performInterruptionComponents in SystemAPI.Query>()) { for (int i = 0; i < performInterruptionComponents.Length; ++i) { var performInterruptionComponent = performInterruptionComponents[i]; if (performInterruptionComponent.InterruptIndicies.IsCreated) { performInterruptionComponent.InterruptIndicies.Dispose(); } } } } } } #endif