#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.Burst; using Unity.Entities; /// /// Utility functions that are used throughout the behavior tree execution. /// [BurstCompile] public static class TraversalUtility { /// /// Returns true if the specified index is a child of the parent index. /// /// The index to determine if it is a child. /// The index of the parent. /// The array of nodes. /// True if the specified index is a child of the parent index. [BurstCompile] public static bool IsParent(ushort index, ushort parentIndex, ref DynamicBuffer taskComponents) { if (parentIndex == ushort.MaxValue || index == ushort.MaxValue) { return false; } // The child can be considered a parent of itself. if (parentIndex == index) { return true; } var parentTaskComponent = taskComponents[parentIndex]; // Fast path: ChildUpperIndex stores the last descendant index for range checks. if (parentTaskComponent.ChildUpperIndex > parentTaskComponent.Index) { return index > parentTaskComponent.Index && index <= parentTaskComponent.ChildUpperIndex; } // ChildUpperIndex may still be uninitialized on deserialized trees. Fall back to parent walking. if (parentTaskComponent.ChildUpperIndex == parentTaskComponent.Index) { if (parentTaskComponent.Index + 1 >= taskComponents.Length || taskComponents[parentTaskComponent.Index + 1].ParentIndex != parentTaskComponent.Index) { return false; } } // Return true as soon as there is a parent. while (index != ushort.MaxValue) { if (index == parentIndex) { return true; } index = taskComponents[index].ParentIndex; } return false; } /// /// Returns the total number of children belonging to the specified node. /// /// The index of the task to retrieve the child count of. /// The array of nodes. /// The total number of children belonging to the specified node. public static int GetChildCount(int index, ref DynamicBuffer taskComponents) { if (index == ushort.MaxValue) { return 0; } var taskComponent = taskComponents[index]; // Fast path: ChildUpperIndex represents the inclusive descendant upper bound. if (taskComponent.ChildUpperIndex > taskComponent.Index) { return taskComponent.ChildUpperIndex - taskComponent.Index; } // ChildUpperIndex can be equal to Index before initialization. Fall back to parent walking. if (taskComponent.ChildUpperIndex == taskComponent.Index) { if (taskComponent.Index + 1 >= taskComponents.Length || taskComponents[taskComponent.Index + 1].ParentIndex != taskComponent.Index) { return 0; } } if (taskComponent.SiblingIndex != ushort.MaxValue) { return taskComponent.SiblingIndex - taskComponent.Index - 1; } if (taskComponent.Index + 1 == taskComponents.Length) { return 0; } var childTaskComponent = taskComponents[taskComponent.Index + 1]; if (childTaskComponent.ParentIndex != taskComponent.Index) { return 0; } // Determine the child count based off of the sibling index. var lastChildTaskComponent = childTaskComponent; while (childTaskComponent.ParentIndex == taskComponent.Index) { lastChildTaskComponent = childTaskComponent; if (childTaskComponent.SiblingIndex == ushort.MaxValue) { break; } childTaskComponent = taskComponents[childTaskComponent.SiblingIndex]; } return lastChildTaskComponent.Index - taskComponent.Index + GetChildCount(lastChildTaskComponent.Index, ref taskComponents); } /// /// Populates each task's child upper bound index. /// /// The task buffer that should be updated. [BurstCompile] public static void PopulateChildUpperIndices(ref DynamicBuffer taskComponents) { for (int i = 0; i < taskComponents.Length; ++i) { var taskComponent = taskComponents[i]; var childCount = GetChildCount(taskComponent.Index, ref taskComponents); taskComponent.ChildUpperIndex = (ushort)(taskComponent.Index + childCount); taskComponents[i] = taskComponent; } } /// /// Returns the immediate number of children belonging to the specified task. /// /// The task to retrieve the children of. /// The list of tasks. /// The number of immediate children belonging to the specified task. [BurstCompile] public static int GetImmediateChildCount(ref TaskComponent task, ref DynamicBuffer taskComponents) { var count = 0; var siblingIndex = task.Index + 1; while (siblingIndex < taskComponents.Length && taskComponents[siblingIndex].ParentIndex == task.Index) { count++; siblingIndex = taskComponents[siblingIndex].SiblingIndex; } return count; } } } #endif