/// --------------------------------------------- /// Behavior Designer /// Copyright (c) Opsive. All Rights Reserved. /// https://www.opsive.com /// --------------------------------------------- namespace Opsive.BehaviorDesigner.Samples { using Opsive.BehaviorDesigner.Runtime.Components; using Opsive.BehaviorDesigner.Runtime.Tasks; using Opsive.GraphDesigner.Runtime.Variables; using Opsive.GraphDesigner.Runtime.Variables.ECS; using Unity.Burst; using Unity.Entities; using UnityEngine; [Opsive.Shared.Utility.Description("Uses DOTS to determine if the entity has a target.")] [Shared.Utility.Category("Behavior Designer Samples/DOTS")] public class HasTarget : ECSConditionalTask, IReevaluateResponder { [Tooltip("The entity that should be targeted.")] [SerializeField] [RequireShared] SharedVariable m_TargetEntity; private ECSSharedVariableIndex m_TargetEntityIndex; public ComponentType ReevaluateFlag { get => typeof(HasTargetReevaluateFlag); } public System.Type ReevaluateSystemType { get => typeof(HasTargetReevaluateTaskSystem); } /// /// Registers the target SharedVariable and adds the buffer element to the entity. /// /// The world that the entity exists in. /// The entity that the IBufferElementData should be assigned to. /// The ECS variable registry for registering SharedVariable fields. /// The GameObject that the entity is attached to. /// The index of the element within the buffer. public override int AddBufferElement(World world, Entity entity, ECSVariableRegistry registry, GameObject gameObject) { m_TargetEntityIndex = new ECSSharedVariableIndex(registry.Register(m_TargetEntity)); return base.AddBufferElement(world, entity, registry, gameObject); } /// /// Returns a new TBufferElement for use by the system. /// /// A new TBufferElement for use by the system. public override HasTargetComponent GetBufferElement() { return new HasTargetComponent() { Index = RuntimeIndex, TargetEntityVariableIndex = m_TargetEntityIndex.Index, }; } } /// /// The DOTS data structure for the HasTarget struct. /// public struct HasTargetComponent : IBufferElementData { [Tooltip("The index of the node.")] public ushort Index; [Tooltip("Buffer index into SharedVariableElement for the target entity.")] public int TargetEntityVariableIndex; } /// /// A DOTS flag indicating when a HasTarget node is active. /// public struct HasTargetFlag : IComponentData, IEnableableComponent { } /// /// Runs the HasTarget logic. /// [DisableAutoCreation] public partial struct HasTargetTaskSystem : ISystem { /// /// Updates the logic. /// /// The current state of the system. [BurstCompile] private void OnUpdate(ref SystemState state) { foreach (var (branchComponents, taskComponents, hasTargetComponents, sharedVariables) in SystemAPI.Query, DynamicBuffer, DynamicBuffer, DynamicBuffer>().WithAll()) { for (int i = 0; i < hasTargetComponents.Length; ++i) { var hasTargetComponent = hasTargetComponents[i]; var taskComponent = taskComponents[hasTargetComponent.Index]; var branchComponent = branchComponents[taskComponent.BranchIndex]; if (!branchComponent.CanExecute) { continue; } if (taskComponent.Status != TaskStatus.Queued) { continue; } var targetEntity = sharedVariables.Get(hasTargetComponent.TargetEntityVariableIndex); var hasTarget = targetEntity != Entity.Null && state.EntityManager.Exists(targetEntity); taskComponent.Status = hasTarget ? TaskStatus.Success : TaskStatus.Failure; var taskComponentBuffer = taskComponents; taskComponentBuffer[hasTargetComponent.Index] = taskComponent; } } } } /// /// A DOTS tag indicating when an HasTarget node needs to be reevaluated. /// public struct HasTargetReevaluateFlag : IComponentData, IEnableableComponent { } /// /// Runs the HasTarget reevaluation logic. /// [DisableAutoCreation] public partial struct HasTargetReevaluateTaskSystem : ISystem { /// /// Updates the reevaluation logic. /// /// The current state of the system. [BurstCompile] private void OnUpdate(ref SystemState state) { foreach (var (branchComponents, taskComponents, hasTargetComponents, sharedVariables) in SystemAPI.Query, DynamicBuffer, DynamicBuffer, DynamicBuffer>().WithAll()) { for (int i = 0; i < hasTargetComponents.Length; ++i) { var hasTargetComponent = hasTargetComponents[i]; var taskComponent = taskComponents[hasTargetComponent.Index]; var branchComponent = branchComponents[taskComponent.BranchIndex]; if (!branchComponent.CanExecute) { continue; } if (!taskComponent.Reevaluate) { continue; } var targetEntity = sharedVariables.Get(hasTargetComponent.TargetEntityVariableIndex); var hasTarget = targetEntity != Entity.Null && state.EntityManager.Exists(targetEntity); var status = hasTarget ? TaskStatus.Success : TaskStatus.Failure; if (status != taskComponent.Status) { taskComponent.Status = status; var buffer = taskComponents; buffer[taskComponent.Index] = taskComponent; } } } } } }