#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