#if GRAPH_DESIGNER
/// ---------------------------------------------
/// Behavior Designer
/// Copyright (c) Opsive. All Rights Reserved.
/// https://www.opsive.com
/// ---------------------------------------------
namespace Opsive.BehaviorDesigner.Runtime.Components
{
using Opsive.BehaviorDesigner.Runtime.Groups;
using Unity.Entities;
using UnityEngine;
///
/// Indicates that the behavior tree was baked.
///
public class BakedBehaviorTree : IComponentData
{
[Tooltip("The index of the connected start task.")]
public int StartEventConnectedIndex;
[Tooltip("Should the behavior tree be started after it has been baked?")]
public bool StartEvaluation;
[Tooltip("The indicies of the reevaluate task systems.")]
public string[] ReevaluateTaskSystems;
[Tooltip("The indicies of the interrupt task systems.")]
public string[] InterruptTaskSystems;
[Tooltip("The indicies of the traversal task systems.")]
public string[] TraversalTaskSystems;
[Tooltip("The hashes that correspond to the TaskComponent's ComponentType.")]
public ulong[] TagStableTypeHashes;
[Tooltip("The hashes that correspond to the ReevaluateTaskComponent's ComponentType.")]
public ulong[] ReevaluateTagStableTypeHashes;
}
///
/// The behavior tree has been baked. Start the tree using the baked data.
///
public partial struct StartBakedBehaviorTreeSystem : ISystem
{
///
/// Restricts when the system should run.
///
/// The current SystemState.
private void OnCreate(ref SystemState state)
{
state.RequireForUpdate();
state.Enabled = false;
}
///
/// Starts the baked behavior tree.
///
/// The current SystemState.
private void OnUpdate(ref SystemState state)
{
state.Enabled = false;
// The components are baked, but systems are not baked. Create the required systems within the current world.
var reevaluateTaskSystemGroup = state.World.GetOrCreateSystemManaged();
var interruptTaskSystemGroup = state.World.GetOrCreateSystemManaged();
var traversalTaskSystemGroup = state.World.GetOrCreateSystemManaged();
var ecb = new EntityCommandBuffer(state.WorldUpdateAllocator);
foreach (var (bakedBehaviorTree, entity) in SystemAPI.Query().WithEntityAccess()) {
AddSystems(state.World, reevaluateTaskSystemGroup, bakedBehaviorTree.ReevaluateTaskSystems);
AddSystems(state.World, interruptTaskSystemGroup, bakedBehaviorTree.InterruptTaskSystems);
AddSystems(state.World, traversalTaskSystemGroup, bakedBehaviorTree.TraversalTaskSystems);
// ComponentTypes cannot be serialized. Convert the StableTypeHash to a ComponentType.
var taskComponents = state.World.EntityManager.GetBuffer(entity);
for (int i = 0; i < taskComponents.Length; ++i) {
var taskComponent = taskComponents[i];
taskComponent.TagComponentType = ComponentType.FromTypeIndex(TypeManager.GetTypeIndexFromStableTypeHash(bakedBehaviorTree.TagStableTypeHashes[i]));
taskComponents[i] = taskComponent;
}
if (state.World.EntityManager.HasBuffer(entity)) {
var reevaluateComponents = state.World.EntityManager.GetBuffer(entity);
for (int i = 0; i < reevaluateComponents.Length; ++i) {
var reevaluateComponent = reevaluateComponents[i];
reevaluateComponent.ReevaluateTagComponentType = ComponentType.FromTypeIndex(TypeManager.GetTypeIndexFromStableTypeHash(bakedBehaviorTree.ReevaluateTagStableTypeHashes[i]));
reevaluateComponents[i] = reevaluateComponent;
}
}
// All of the systems have been added. Start the behavior tree.
BehaviorTree.StartBranch(state.World, entity, (ushort)bakedBehaviorTree.StartEventConnectedIndex, bakedBehaviorTree.StartEvaluation);
ecb.RemoveComponent(entity);
}
ecb.Playback(state.EntityManager);
ecb.Dispose();
}
///
/// Adds the systems indicated by the SystemTypeIndex to the specified group.
///
/// The current World.
/// The group that the systems should be added to.
/// The types of systems that should be added.
private void AddSystems(World world, ComponentSystemGroup group, string[] systemTypes)
{
if (systemTypes == null) { return; }
for (int i = 0; i < systemTypes.Length; ++i) {
group.AddSystemToUpdateList(world.GetOrCreateSystem(Shared.Utility.TypeUtility.GetType(systemTypes[i])));
}
}
}
}
#endif