#if GRAPH_DESIGNER /// --------------------------------------------- /// Behavior Designer /// Copyright (c) Opsive. All Rights Reserved. /// https://www.opsive.com /// --------------------------------------------- namespace Opsive.BehaviorDesigner.Runtime.Utility { using Opsive.BehaviorDesigner.Runtime.Components; using Unity.Collections; using Unity.Entities; /// /// Utility functions that are used throughout the behavior tree execution. /// public static class ComponentUtility { /// /// The size of a ulong in bits. /// public static int ulongBitSize => sizeof(ulong) * 8; /// /// Adds an evaluation component to the specified entity based on the task count and evaluation type. /// /// The ECS world to add the component to. /// The entity to add the evaluation component to. /// The total number of tasks in the behavior tree. /// The type of evaluation to perform. /// The maximum number of evaluations allowed. public static void AddEvaluationComponent(World world, Entity entity, int taskCount, EvaluationType evaluationType, int maxEvaluationCount) { // Both EvaluationType.EntireTree and EvaluationType.Count use a bitmask to track evaluated tasks. // For Count mode, an additional element is reserved at the end to store the execution count. var bitmaskElementCount = taskCount / ulongBitSize + 1; var countModeExtraElement = evaluationType == EvaluationType.Count ? 1 : 0; if (taskCount < 192) { world.EntityManager.AddComponent(entity); var evaluatedTasks = new FixedList32Bytes(); for (int i = 0; i < bitmaskElementCount + countModeExtraElement; ++i) { evaluatedTasks.Add(0); } world.EntityManager.AddComponentData(entity, new EvaluationComponent32() { EvaluationType = evaluationType, MaxEvaluationCount = (ushort)UnityEngine.Mathf.Max(1, maxEvaluationCount), EvaluatedTasks = evaluatedTasks }); } else if (taskCount < 448) { world.EntityManager.AddComponent(entity); var evaluatedTasks = new FixedList64Bytes(); for (int i = 0; i < bitmaskElementCount + countModeExtraElement; ++i) { evaluatedTasks.Add(0); } world.EntityManager.AddComponentData(entity, new EvaluationComponent64() { EvaluationType = evaluationType, MaxEvaluationCount = (ushort)UnityEngine.Mathf.Max(1, maxEvaluationCount), EvaluatedTasks = evaluatedTasks }); } else if (taskCount < 960) { world.EntityManager.AddComponent(entity); var evaluatedTasks = new FixedList128Bytes(); for (int i = 0; i < bitmaskElementCount + countModeExtraElement; ++i) { evaluatedTasks.Add(0); } world.EntityManager.AddComponentData(entity, new EvaluationComponent128() { EvaluationType = evaluationType, MaxEvaluationCount = (ushort)UnityEngine.Mathf.Max(1, maxEvaluationCount), EvaluatedTasks = evaluatedTasks }); } else if (taskCount < 4032) { world.EntityManager.AddComponent(entity); var evaluatedTasks = new FixedList512Bytes(); for (int i = 0; i < bitmaskElementCount + countModeExtraElement; ++i) { evaluatedTasks.Add(0); } world.EntityManager.AddComponentData(entity, new EvaluationComponent512() { EvaluationType = evaluationType, MaxEvaluationCount = (ushort)UnityEngine.Mathf.Max(1, maxEvaluationCount), EvaluatedTasks = evaluatedTasks }); } else if (taskCount < 32704) { world.EntityManager.AddComponent(entity); var evaluatedTasks = new FixedList4096Bytes(); for (int i = 0; i < bitmaskElementCount + countModeExtraElement; ++i) { evaluatedTasks.Add(0); } world.EntityManager.AddComponentData(entity, new EvaluationComponent4096() { EvaluationType = evaluationType, MaxEvaluationCount = (ushort)UnityEngine.Mathf.Max(1, maxEvaluationCount), EvaluatedTasks = evaluatedTasks }); } else { UnityEngine.Debug.LogError("Error: Trees with more than 32,703 tasks are not supported. Please email support@opsive.com."); } } /// /// Resets the evaluation component data for the specified entity by clearing all evaluated task flags. /// /// The ECS world containing the entity. /// The entity whose evaluation component should be reset. public static void ResetEvaluationComponent(World world, Entity entity) { if (world.EntityManager.HasComponent(entity)) { var evaluateComponent = world.EntityManager.GetComponentData(entity); var evaluatedTasks = evaluateComponent.EvaluatedTasks; for (int i = 0; i < evaluatedTasks.Length; ++i) { evaluatedTasks[i] = 0; } evaluateComponent.EvaluatedTasks = evaluatedTasks; world.EntityManager.SetComponentData(entity, evaluateComponent); } else if (world.EntityManager.HasComponent(entity)) { var evaluateComponent = world.EntityManager.GetComponentData(entity); var evaluatedTasks = evaluateComponent.EvaluatedTasks; for (int i = 0; i < evaluatedTasks.Length; ++i) { evaluatedTasks[i] = 0; } evaluateComponent.EvaluatedTasks = evaluatedTasks; world.EntityManager.SetComponentData(entity, evaluateComponent); } else if (world.EntityManager.HasComponent(entity)) { var evaluateComponent = world.EntityManager.GetComponentData(entity); var evaluatedTasks = evaluateComponent.EvaluatedTasks; for (int i = 0; i < evaluatedTasks.Length; ++i) { evaluatedTasks[i] = 0; } evaluateComponent.EvaluatedTasks = evaluatedTasks; world.EntityManager.SetComponentData(entity, evaluateComponent); } else if (world.EntityManager.HasComponent(entity)) { var evaluateComponent = world.EntityManager.GetComponentData(entity); var evaluatedTasks = evaluateComponent.EvaluatedTasks; for (int i = 0; i < evaluatedTasks.Length; ++i) { evaluatedTasks[i] = 0; } evaluateComponent.EvaluatedTasks = evaluatedTasks; world.EntityManager.SetComponentData(entity, evaluateComponent); } else if (world.EntityManager.HasComponent(entity)) { var evaluateComponent = world.EntityManager.GetComponentData(entity); var evaluatedTasks = evaluateComponent.EvaluatedTasks; for (int i = 0; i < evaluatedTasks.Length; ++i) { evaluatedTasks[i] = 0; } evaluateComponent.EvaluatedTasks = evaluatedTasks; world.EntityManager.SetComponentData(entity, evaluateComponent); } } /// /// Removes the evaluation component from the specified entity. /// /// The ECS world containing the entity. /// The entity whose evaluation component should be removed. public static void RemoveEvaluationComponent(World world, Entity entity) { if (world.EntityManager.HasComponent(entity)) { world.EntityManager.RemoveComponent(entity); } else if (world.EntityManager.HasComponent(entity)) { world.EntityManager.RemoveComponent(entity); } else if (world.EntityManager.HasComponent(entity)) { world.EntityManager.RemoveComponent(entity); } else if (world.EntityManager.HasComponent(entity)) { world.EntityManager.RemoveComponent(entity); } else if (world.EntityManager.HasComponent(entity)) { world.EntityManager.RemoveComponent(entity); } } /// /// Adds the components necessary in order to trigger an interrupt. /// /// The EntityManager that the entity belongs to. /// The entity that should have the components added. public static void AddInterruptComponents(EntityManager entityManager, Entity entity) { entityManager.AddComponent(entity); entityManager.SetComponentEnabled(entity, false); entityManager.AddComponent(entity); entityManager.SetComponentEnabled(entity, false); } } } #endif