chore: initial commit
This commit is contained in:
1983
Packages/com.opsive.behaviordesigner/Runtime/BehaviorTree.cs
Normal file
1983
Packages/com.opsive.behaviordesigner/Runtime/BehaviorTree.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0cdaa3305fa954c45a80c9662aa6f425
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: e0a8f1df788b6274a9a24003859dfa7e, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1674
Packages/com.opsive.behaviordesigner/Runtime/BehaviorTreeData.cs
Normal file
1674
Packages/com.opsive.behaviordesigner/Runtime/BehaviorTreeData.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b88607c73749e1f47b8bb1ed0b34a7a8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,117 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime
|
||||
{
|
||||
using Opsive.BehaviorDesigner.Runtime.Tasks;
|
||||
using Opsive.GraphDesigner.Runtime;
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using Opsive.Shared.Utility;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Storage class for the graph data.
|
||||
/// </summary>
|
||||
public partial class BehaviorTreeData
|
||||
{
|
||||
/// <summary>
|
||||
/// Data structure which contains the properties for a subtree that will be injected.
|
||||
/// </summary>
|
||||
private struct SubtreeAssignment
|
||||
{
|
||||
[Tooltip("The index of the SubtreeNodesReference element.")]
|
||||
public int ReferenceIndex;
|
||||
[Tooltip("The index of the ISubtreeReference task.")]
|
||||
public ushort NodeIndex;
|
||||
[Tooltip("The index of the Subtree.")]
|
||||
public int SubtreeIndex;
|
||||
[Tooltip("The subtree that the task references.")]
|
||||
public Subtree Subtree;
|
||||
[Tooltip("The offset of the index. This will change as subtrees are added.")]
|
||||
public ushort IndexOffset;
|
||||
[Tooltip("The original parent index of the ISubtreeReference task.")]
|
||||
public ushort ParentIndex;
|
||||
[Tooltip("The original sibling index of the ISubtreeReference task.")]
|
||||
public ushort SiblingIndex;
|
||||
[Tooltip("The number of nodes that are a child of the ISubtreeReference.")]
|
||||
public ushort NodeCount;
|
||||
#if UNITY_EDITOR
|
||||
[Tooltip("The position of the ISubtreeReference task.")]
|
||||
public Vector2 NodePropertiesPosition;
|
||||
[Tooltip("Is the ISubtreeReference task collapsed?")]
|
||||
public bool Collapsed;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contains a reference to the subtree index and nodes.
|
||||
/// </summary>
|
||||
internal struct SubtreeNodesReference
|
||||
{
|
||||
[Tooltip("The ISubtreeReference.")]
|
||||
public ISubtreeReference SubtreeReference;
|
||||
[Tooltip("The index of the ISubtreeReference.")]
|
||||
public ushort NodeIndex;
|
||||
[Tooltip("The total number of nodes contained within the ISubtreeReference.")]
|
||||
public ushort NodeCount;
|
||||
[Tooltip("A reference to the subtrees that are loaded.")]
|
||||
public Subtree[] Subtrees;
|
||||
[Tooltip("The deserialized nodes.")]
|
||||
public ITreeLogicNode[][] Nodes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Keeps a reference to the graph variables allowing them to be overwritten if a subtree is set.
|
||||
/// </summary>
|
||||
private struct VariableField
|
||||
{
|
||||
[Tooltip("The field that the SharedVariable is assigned to.")]
|
||||
public FieldInfo Field;
|
||||
[Tooltip("The task that the SharedVariable is assigned to.")]
|
||||
public object Task;
|
||||
[Tooltip("The name of the SharedVariable.")]
|
||||
public string Name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal data structure for referencing a SharedVariable to its name/scope.
|
||||
/// </summary>
|
||||
public struct VariableAssignment
|
||||
{
|
||||
[Tooltip("The name of the SharedVariable.")]
|
||||
public PropertyName Name;
|
||||
[Tooltip("The scope of the SharedVariable.")]
|
||||
public SharedVariable.SharingScope Scope;
|
||||
|
||||
/// <summary>
|
||||
/// VariableAssignment constructor.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the SharedVariable.</param>
|
||||
/// <param name="scope">The scope of the SharedVariable.</param>
|
||||
public VariableAssignment(PropertyName name, SharedVariable.SharingScope scope)
|
||||
{
|
||||
Name = name;
|
||||
Scope = scope;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal data structure for restoring a task reference after it has been deserialized.
|
||||
/// </summary>
|
||||
public struct TaskAssignment
|
||||
{
|
||||
[Tooltip("The field of the task.")]
|
||||
public FieldInfo Field;
|
||||
[Tooltip("The task that the field belongs to.")]
|
||||
public object Target;
|
||||
[Tooltip("The value of the field. This will be the task object that should be assigned after the tree has been loaded.")]
|
||||
public object Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ca426c026a6a06469dc2d4a512ef855
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f13872ff04404c4da862a21fe89cac6
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,120 @@
|
||||
#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 Opsive.BehaviorDesigner.Runtime.Systems;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the behavior tree was baked.
|
||||
/// </summary>
|
||||
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[] ReevaluateFlagStableTypeHashes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The behavior tree has been baked. Start the tree using the baked data.
|
||||
/// </summary>
|
||||
public partial struct StartBakedBehaviorTreeSystem : ISystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Restricts when the system should run.
|
||||
/// </summary>
|
||||
/// <param name="state">The current SystemState.</param>
|
||||
private void OnCreate(ref SystemState state)
|
||||
{
|
||||
state.RequireForUpdate<BakedBehaviorTree>();
|
||||
state.Enabled = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the baked behavior tree.
|
||||
/// </summary>
|
||||
/// <param name="state">The current SystemState.</param>
|
||||
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<ReevaluateTaskSystemGroup>();
|
||||
var interruptTaskSystemGroup = state.World.GetOrCreateSystemManaged<InterruptTaskSystemGroup>();
|
||||
var traversalTaskSystemGroup = state.World.GetOrCreateSystemManaged<TraversalTaskSystemGroup>();
|
||||
|
||||
// Add the necessary cleanup systems.
|
||||
var behaviorTreeSystemGroup = state.World.GetOrCreateSystemManaged<BehaviorTreeSystemGroup>();
|
||||
behaviorTreeSystemGroup.AddSystemToUpdateList(state.World.GetOrCreateSystem<EvaluationCleanupSystem>());
|
||||
behaviorTreeSystemGroup.AddSystemToUpdateList(state.World.GetOrCreateSystem<InterruptedCleanupSystem>());
|
||||
|
||||
var canReevaluate = false;
|
||||
var ecb = new EntityCommandBuffer(state.WorldUpdateAllocator);
|
||||
foreach (var (bakedBehaviorTree, entity) in SystemAPI.Query<BakedBehaviorTree>().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<TaskComponent>(entity);
|
||||
for (int i = 0; i < taskComponents.Length; ++i) {
|
||||
var taskComponent = taskComponents[i];
|
||||
taskComponent.FlagComponentType = ComponentType.FromTypeIndex(TypeManager.GetTypeIndexFromStableTypeHash(bakedBehaviorTree.TagStableTypeHashes[i]));
|
||||
taskComponents[i] = taskComponent;
|
||||
}
|
||||
|
||||
if (state.World.EntityManager.HasBuffer<ReevaluateTaskComponent>(entity)) {
|
||||
var reevaluateComponents = state.World.EntityManager.GetBuffer<ReevaluateTaskComponent>(entity);
|
||||
canReevaluate = true;
|
||||
for (int i = 0; i < reevaluateComponents.Length; ++i) {
|
||||
var reevaluateComponent = reevaluateComponents[i];
|
||||
reevaluateComponent.ReevaluateFlagComponentType = ComponentType.FromTypeIndex(TypeManager.GetTypeIndexFromStableTypeHash(bakedBehaviorTree.ReevaluateFlagStableTypeHashes[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<BakedBehaviorTree>(entity);
|
||||
}
|
||||
if (canReevaluate) {
|
||||
reevaluateTaskSystemGroup.AddSystemToUpdateList(state.World.GetOrCreateSystem<ReevaluateSystem>());
|
||||
}
|
||||
ecb.Playback(state.EntityManager);
|
||||
ecb.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the systems indicated by the SystemTypeIndex to the specified group.
|
||||
/// </summary>
|
||||
/// <param name="world">The current World.</param>
|
||||
/// <param name="group">The group that the systems should be added to.</param>
|
||||
/// <param name="systemTypes">The types of systems that should be added.</param>
|
||||
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
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f68d4eca856988e4a8f4073516e7de57
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,261 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Components
|
||||
{
|
||||
using Opsive.BehaviorDesigner.Runtime.Tasks;
|
||||
using System.Runtime.InteropServices;
|
||||
using Unity.Collections;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// The runtime DOTS data associated with a task.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public struct TaskComponent : IBufferElementData
|
||||
{
|
||||
[Tooltip("The index of the task within the behavior tree.")]
|
||||
public ushort Index;
|
||||
[Tooltip("The index of the parent task within the behavior tree.")]
|
||||
public ushort ParentIndex;
|
||||
//public ushort m_ParentIndex;
|
||||
//public ushort ParentIndex { get { return m_ParentIndex; } set { UnityEngine.Debug.Log(Index + " parent: " + value); m_ParentIndex = value; } }
|
||||
[Tooltip("The index of the sibling task within the behavior tree.")]
|
||||
public ushort SiblingIndex;
|
||||
//public ushort m_SiblingIndex;
|
||||
//public ushort SiblingIndex { get { return m_SiblingIndex; } set { UnityEngine.Debug.Log(Index + " sibling: " + value); m_SiblingIndex = value; } }
|
||||
[Tooltip("The index of the branch the task executes within.")]
|
||||
public ushort BranchIndex;
|
||||
//public ushort m_BranchIndex;
|
||||
//public ushort BranchIndex { get { return m_BranchIndex; } set { UnityEngine.Debug.Log(Index + " branch: " + value); m_BranchIndex = value; } }
|
||||
[Tooltip("The component type responsible for indicating that the task is active.")]
|
||||
public ComponentType FlagComponentType;
|
||||
[Tooltip("Is the task disabled?")]
|
||||
[MarshalAs(UnmanagedType.U1)]
|
||||
public bool Disabled;
|
||||
[Tooltip("The current execution status of the task.")]
|
||||
//public TaskStatus Status;
|
||||
[SerializeField] private TaskStatus m_Status;
|
||||
public TaskStatus Status {
|
||||
get => m_Status;
|
||||
set {
|
||||
m_Status = value;
|
||||
CanReevaluate = value != TaskStatus.Inactive;
|
||||
//UnityEngine.Debug.Log(string.Format("{0} status: {1}", Index, value));
|
||||
}
|
||||
}
|
||||
[Tooltip("Can the task be reevaluated with conditional aborts?")]
|
||||
[MarshalAs(UnmanagedType.U1)]
|
||||
public bool CanReevaluate;
|
||||
[Tooltip("Is the task being reevaluated with conditional aborts?")]
|
||||
[MarshalAs(UnmanagedType.U1)]
|
||||
public bool Reevaluate;
|
||||
//public bool m_Reevaluate;
|
||||
//public bool Reevaluate { get { return m_Reevaluate; } set { UnityEngine.Debug.Log(Index + " reevaluate: " + value + " " + GetHashCode()); m_Reevaluate = value; } }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies when the behavior tree should be updated.
|
||||
/// </summary>
|
||||
public enum UpdateMode
|
||||
{
|
||||
EveryFrame, // The behavior tree should be updated every frame.
|
||||
Manual // The behavior tree should be updated manually via a user script.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies how many tasks should be evaluated. Evaluation will end if all branches return a status of TaskStatus.Running.
|
||||
/// </summary>
|
||||
public enum EvaluationType : byte
|
||||
{
|
||||
EntireTree, // Evaluates up to all of the tasks within the tree.
|
||||
Count // Evaluates up to the specified MaxEvaluationCount.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies if the tree should be evaluated.
|
||||
/// </summary>
|
||||
public struct EvaluationComponent32 : IComponentData
|
||||
{
|
||||
[Tooltip("Specifies how many tasks should be updated during a single tick.")]
|
||||
public EvaluationType EvaluationType;
|
||||
[Tooltip("The maximum number of tasks that can run if the evaluation type is set to EvaluationType.Count.")]
|
||||
public ushort MaxEvaluationCount;
|
||||
[Tooltip("A bitmask of the tasks that have been evaluated. For EvaluationType.Count, the last element stores the execution count.")]
|
||||
public FixedList32Bytes<ulong> EvaluatedTasks;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies if the tree should be evaluated.
|
||||
/// </summary>
|
||||
public struct EvaluationComponent64 : IComponentData
|
||||
{
|
||||
[Tooltip("Specifies how many tasks should be updated during a single tick.")]
|
||||
public EvaluationType EvaluationType;
|
||||
[Tooltip("The maximum number of tasks that can run if the evaluation type is set to EvaluationType.Count.")]
|
||||
public ushort MaxEvaluationCount;
|
||||
[Tooltip("A bitmask of the tasks that have been evaluated. For EvaluationType.Count, the last element stores the execution count.")]
|
||||
public FixedList64Bytes<ulong> EvaluatedTasks;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies if the tree should be evaluated.
|
||||
/// </summary>
|
||||
public struct EvaluationComponent128 : IComponentData
|
||||
{
|
||||
[Tooltip("Specifies how many tasks should be updated during a single tick.")]
|
||||
public EvaluationType EvaluationType;
|
||||
[Tooltip("The maximum number of tasks that can run if the evaluation type is set to EvaluationType.Count.")]
|
||||
public ushort MaxEvaluationCount;
|
||||
[Tooltip("A bitmask of the tasks that have been evaluated. For EvaluationType.Count, the last element stores the execution count.")]
|
||||
public FixedList128Bytes<ulong> EvaluatedTasks;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies if the tree should be evaluated.
|
||||
/// </summary>
|
||||
public struct EvaluationComponent512 : IComponentData
|
||||
{
|
||||
[Tooltip("Specifies how many tasks should be updated during a single tick.")]
|
||||
public EvaluationType EvaluationType;
|
||||
[Tooltip("The maximum number of tasks that can run if the evaluation type is set to EvaluationType.Count.")]
|
||||
public ushort MaxEvaluationCount;
|
||||
[Tooltip("A bitmask of the tasks that have been evaluated. For EvaluationType.Count, the last element stores the execution count.")]
|
||||
public FixedList512Bytes<ulong> EvaluatedTasks;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies if the tree should be evaluated.
|
||||
/// </summary>
|
||||
public struct EvaluationComponent4096 : IComponentData
|
||||
{
|
||||
[Tooltip("Specifies how many tasks should be updated during a single tick.")]
|
||||
public EvaluationType EvaluationType;
|
||||
[Tooltip("The maximum number of tasks that can run if the evaluation type is set to EvaluationType.Count.")]
|
||||
public ushort MaxEvaluationCount;
|
||||
[Tooltip("A bitmask of the tasks that have been evaluated. For EvaluationType.Count, the last element stores the execution count.")]
|
||||
public FixedList4096Bytes<ulong> EvaluatedTasks;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies how the branch was interrupted.
|
||||
/// </summary>
|
||||
public enum InterruptType : byte
|
||||
{
|
||||
None, // No interrupt.
|
||||
Branch, // A conditional abort or utility selector triggered the interruption.
|
||||
ImmediateSuccess, // The branch was interrupted with a success status.
|
||||
ImmediateFailure, // The branch was interrupted with a failure status.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The runtime DOTS data associated with a branch.
|
||||
/// </summary>
|
||||
public struct BranchComponent : IBufferElementData
|
||||
{
|
||||
[Tooltip("The index of the task that is currently active.")]
|
||||
public ushort ActiveIndex;
|
||||
//public ushort m_ActiveIndex;
|
||||
//public ushort ActiveIndex { get { return m_ActiveIndex; } set { Debug.Log(string.Format("Active: {0}", value)); m_ActiveIndex = value; } }
|
||||
[Tooltip("The index of the task that should execute next.")]
|
||||
public ushort NextIndex;
|
||||
//public ushort m_NextIndex;
|
||||
//public ushort NextIndex { get { return m_NextIndex; } set { Debug.Log(string.Format("Next: {0}", value)); m_NextIndex = value; } }
|
||||
[Tooltip("The index of the last active task.")]
|
||||
public ushort LastActiveIndex;
|
||||
[Tooltip("The component tag that is active.")]
|
||||
public ComponentType ActiveFlagComponentType;
|
||||
//public ComponentType m_ActiveFlagComponentType;
|
||||
//public ComponentType ActiveFlagComponentType { get { return m_ActiveFlagComponentType; } set { Debug.Log(string.Format("Tag: {0}", value)); m_ActiveFlagComponentType = value; } }
|
||||
[Tooltip("Specifies how the branch is interrupted.")]
|
||||
public InterruptType InterruptType;
|
||||
//public InterruptType m_InterruptType;
|
||||
//public InterruptType InterruptType { get { return m_InterruptType; } set { m_InterruptType = value; Debug.Log("Interrupt Type " + value); } }
|
||||
[Tooltip("The index of the task that caused an interruption. A value of 0 indicates no interruption.")]
|
||||
public ushort InterruptIndex;
|
||||
[Tooltip("Specifies if the branch can execute tasks. Set to false when all tasks in the branch have executed this tick.")]
|
||||
public bool CanExecute;
|
||||
//public bool m_CanExecute;
|
||||
//public bool CanExecute { get { return m_CanExecute; } set { m_CanExecute = value; Debug.Log("Can Execute " + value); } }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies if the tree can be evaluated.
|
||||
/// </summary>
|
||||
public struct EvaluateFlag : IComponentData, IEnableableComponent { }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies if the tree is enabled.
|
||||
/// </summary>
|
||||
public struct EnabledFlag : IComponentData, IEnableableComponent { }
|
||||
|
||||
/// <summary>
|
||||
/// Flag used to indicate when the branch should be interrupted.
|
||||
/// </summary>
|
||||
public struct InterruptFlag : IComponentData, IEnableableComponent { }
|
||||
|
||||
/// <summary>
|
||||
/// Flag used to indicate that the branch has been interrupted.
|
||||
/// </summary>
|
||||
public struct InterruptedFlag : IComponentData, IEnableableComponent { }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the reevaluation status of the task.
|
||||
/// </summary>
|
||||
public enum ReevaluateStatus : byte
|
||||
{
|
||||
Inactive, // The task is not being reevaluated.
|
||||
Active, // The task is currently being reevaluated.
|
||||
Dirty // The task was reevaluated and triggered a change.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The runtime DOTS data associated with conditional aborts.
|
||||
/// </summary>
|
||||
public struct ReevaluateTaskComponent : IBufferElementData
|
||||
{
|
||||
[Tooltip("The index of the task.")]
|
||||
public ushort Index;
|
||||
[Tooltip("The type of conditional abort.")]
|
||||
public ConditionalAbortType AbortType;
|
||||
[Tooltip("The lower bound index of the next task if a lower priority abort is specified.")]
|
||||
public ushort LowerPriorityLowerIndex;
|
||||
[Tooltip("The upper bound index of the next task if a lower priority abort is specified.")]
|
||||
public ushort LowerPriorityUpperIndex;
|
||||
[Tooltip("The upper bound index of the next task if a self priority abort is specified.")]
|
||||
public ushort SelfPriorityUpperIndex;
|
||||
[Tooltip("The original status of the task.")]
|
||||
public TaskStatus OriginalStatus;
|
||||
[Tooltip("The tag specifiying the task should be reevaluated.")]
|
||||
public ComponentType ReevaluateFlagComponentType;
|
||||
[Tooltip("The current reevaluation status of the task.")]
|
||||
public ReevaluateStatus ReevaluateStatus;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runtime representation of IEventNodes that can run its own entity logic.
|
||||
/// </summary>
|
||||
public interface IEventNodeEntityReceiver
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds the IBufferElementData to the entity.
|
||||
/// </summary>
|
||||
/// <param name="world">The world that the entity exists in.</param>
|
||||
/// <param name="entity">The entity that the IBufferElementData should be assigned to.</param>
|
||||
/// <param name="gameObject">The GameObject that the entity is attached to.</param>
|
||||
/// <param name="taskOffset">The offset between the connected index and the runtime index.</param>
|
||||
void AddBufferElement(World world, Entity entity, GameObject gameObject, ushort taskOffset);
|
||||
|
||||
/// <summary>
|
||||
/// Clears the IBufferElementData from the entity.
|
||||
/// </summary>
|
||||
/// <param name="world">The world that the entity exists in.</param>
|
||||
/// <param name="entity">The entity that the IBufferElementData should be cleared from.</param>
|
||||
void ClearBufferElement(World world, Entity entity);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 12b6df69a20daeb4ab4ce1ccaa7bc7ec
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Packages/com.opsive.behaviordesigner/Runtime/Groups.meta
Normal file
8
Packages/com.opsive.behaviordesigner/Runtime/Groups.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d9c918e9af659ea4fb420fd6af1433b7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,46 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Groups
|
||||
{
|
||||
using Opsive.BehaviorDesigner.Runtime.Systems;
|
||||
using Unity.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Grouping for the systems that should before other systems.
|
||||
/// </summary>
|
||||
[UpdateInGroup(typeof(BehaviorTreeSystemGroup), OrderFirst = true)]
|
||||
public partial class BeforeTraversalSystemGroup : ComponentSystemGroup
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Grouping for the task systems that should reevaluate.
|
||||
/// </summary>
|
||||
[UpdateInGroup(typeof(BeforeTraversalSystemGroup))]
|
||||
public partial class ReevaluateTaskSystemGroup : ComponentSystemGroup
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Grouping for the systems that run before the tree execution.
|
||||
/// </summary>
|
||||
[UpdateInGroup(typeof(BehaviorTreeSystemGroup))]
|
||||
public partial class InterruptSystemGroup : ComponentSystemGroup
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Grouping for the task systems that can cause interrupts.
|
||||
/// </summary>
|
||||
[UpdateInGroup(typeof(InterruptSystemGroup))]
|
||||
[UpdateAfter(typeof(InterruptSystem))]
|
||||
[UpdateBefore(typeof(InterruptCleanupSystem))]
|
||||
public partial class InterruptTaskSystemGroup : ComponentSystemGroup
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 83e6fa82f6125e140a3d0bd4737feeb3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,80 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Groups
|
||||
{
|
||||
using Opsive.BehaviorDesigner.Runtime.Systems;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// System group which runs all of the behavior tree systems.
|
||||
/// </summary>
|
||||
[UpdateInGroup(typeof(SimulationSystemGroup))]
|
||||
[UpdateAfter(typeof(BeginSimulationEntityCommandBufferSystem))]
|
||||
public partial class BehaviorTreeSystemGroup : ComponentSystemGroup
|
||||
{
|
||||
private bool m_Alive;
|
||||
|
||||
public bool Alive { get => m_Alive; }
|
||||
|
||||
/// <summary>
|
||||
/// Disable the group if there are no behavior trees.
|
||||
/// </summary>
|
||||
[RuntimeInitializeOnLoadMethod]
|
||||
private static void Init()
|
||||
{
|
||||
if (BehaviorTree.BehaviorTreeCount > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var worlds = World.All;
|
||||
for (int i = 0; i < worlds.Count; ++i) {
|
||||
var systemGroup = worlds[i].GetExistingSystemManaged<BehaviorTreeSystemGroup>();
|
||||
if (systemGroup == null) {
|
||||
continue;
|
||||
}
|
||||
systemGroup.Enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The group has been created.
|
||||
/// </summary>
|
||||
protected override void OnCreate()
|
||||
{
|
||||
base.OnCreate();
|
||||
|
||||
m_Alive = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the system group.
|
||||
/// </summary>
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
base.OnUpdate();
|
||||
|
||||
// Stop running if all trees have completed.
|
||||
var systemHandle = World.GetExistingSystem<DetermineEvaluationSystem>();
|
||||
var system = EntityManager.WorldUnmanaged.GetUnsafeSystemRef<DetermineEvaluationSystem>(systemHandle);
|
||||
if (!system.Active) {
|
||||
Enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The group has been destroyed.
|
||||
/// </summary>
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
|
||||
m_Alive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 905219e69953a5e479911f095744ec54
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,41 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Groups
|
||||
{
|
||||
using System;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Group that executes all of the tasks.
|
||||
/// </summary>
|
||||
[UpdateInGroup(typeof(TraversalSystemGroup))]
|
||||
public partial class TraversalTaskSystemGroup : ComponentSystemGroup
|
||||
{
|
||||
[Tooltip("Callback before the outher tasks are updated.")]
|
||||
public Action OnPreUpdate;
|
||||
[Tooltip("Callback after the outher tasks are updated.")]
|
||||
public Action OnPostUpdate;
|
||||
|
||||
/// <summary>
|
||||
/// Updates the group.
|
||||
/// </summary>
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
if (OnPreUpdate != null) {
|
||||
OnPreUpdate();
|
||||
}
|
||||
|
||||
base.OnUpdate();
|
||||
|
||||
if (OnPostUpdate != null) {
|
||||
OnPostUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f48a72a09e70b944a82639a4d549f090
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,76 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Groups
|
||||
{
|
||||
using Opsive.BehaviorDesigner.Runtime.Systems;
|
||||
using Unity.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Main group for the systems that are responsible for traversing the behavior tree.
|
||||
/// </summary>
|
||||
[UpdateInGroup(typeof(BehaviorTreeSystemGroup))]
|
||||
[UpdateAfter(typeof(InterruptSystemGroup))]
|
||||
public partial class TraversalSystemGroup : ComponentSystemGroup
|
||||
{
|
||||
private SystemHandle m_EvaluationSystemHandle;
|
||||
private SystemHandle m_DetermineEvaluationSystemHandle;
|
||||
|
||||
/// <summary>
|
||||
/// The group has been created.
|
||||
/// </summary>
|
||||
protected override void OnCreate()
|
||||
{
|
||||
base.OnCreate();
|
||||
|
||||
m_EvaluationSystemHandle = World.GetExistingSystem<EvaluationSystem>();
|
||||
m_DetermineEvaluationSystemHandle = World.GetExistingSystem<DetermineEvaluationSystem>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the systems. Determines if the systems need to keep being evaluated.
|
||||
/// </summary>
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
var count = 0;
|
||||
#endif
|
||||
bool evaluate;
|
||||
do {
|
||||
base.OnUpdate();
|
||||
|
||||
var determineEvaluationSystem = EntityManager.WorldUnmanaged.GetUnsafeSystemRef<DetermineEvaluationSystem>(m_DetermineEvaluationSystemHandle);
|
||||
determineEvaluationSystem.Complete(EntityManager);
|
||||
evaluate = determineEvaluationSystem.Evaluate;
|
||||
|
||||
var evaluationSystem = EntityManager.WorldUnmanaged.GetUnsafeSystemRef<EvaluationSystem>(m_EvaluationSystemHandle);
|
||||
evaluationSystem.Complete(EntityManager);
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (evaluate) {
|
||||
count++;
|
||||
if (count == ushort.MaxValue / 10) {
|
||||
UnityEngine.Debug.LogWarning("An infinite loop would have been caused by the TraversalSystemGroup. Please email support@opsive.com with steps to reproduce this error.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} while (evaluate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The group has stopped running.
|
||||
/// </summary>
|
||||
protected override void OnStopRunning()
|
||||
{
|
||||
base.OnStopRunning();
|
||||
|
||||
var evaluationSystem = EntityManager.WorldUnmanaged.GetUnsafeSystemRef<EvaluationSystem>(m_EvaluationSystemHandle);
|
||||
evaluationSystem.Complete(EntityManager, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2c1ad397e3cdf7a44ae172b5ae92c2e4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "Opsive.BehaviorDesigner.Runtime",
|
||||
"rootNamespace": "Opsive.BehaviorDesigner.Runtime",
|
||||
"references": [
|
||||
"GUID:e9319bc8ab9315745bdf80aeffa01d6d",
|
||||
"GUID:d8e89a79cd8df884b8d5b3356783eb74",
|
||||
"GUID:734d92eba21c94caba915361bd5ac177",
|
||||
"GUID:2665a8d13d1b3f18800f46e256720795",
|
||||
"GUID:e0cd26848372d4e5c891c569017e11f1",
|
||||
"GUID:d8b63aba1907145bea998dd612889d6b",
|
||||
"GUID:a5baed0c9693541a5bd947d336ec7659",
|
||||
"GUID:8819f35a0fc84499b990e90a4ca1911f"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [
|
||||
{
|
||||
"name": "com.unity.entities",
|
||||
"expression": "1.3.5",
|
||||
"define": "UNITY_ENTITIES"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f9fbcd65fc33f6847b0f124cf7e891b6
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
298
Packages/com.opsive.behaviordesigner/Runtime/Subtree.cs
Normal file
298
Packages/com.opsive.behaviordesigner/Runtime/Subtree.cs
Normal file
@@ -0,0 +1,298 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime;
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// The behavior tree stored within a Scriptable Object.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "Subtree", menuName = "Opsive/Behavior Designer/Subtree", order = 1)]
|
||||
public class Subtree : ScriptableObject, IGraph, ISharedVariableContainer
|
||||
{
|
||||
[Tooltip("The behavior tree data.")]
|
||||
[SerializeField] private BehaviorTreeData m_Data = new BehaviorTreeData();
|
||||
|
||||
public string Name { get => name; set => name = value; }
|
||||
public SharedVariable.SharingScope VariableScope { get => SharedVariable.SharingScope.Graph; }
|
||||
public BehaviorTreeData Data { get => m_Data; }
|
||||
public UnityEngine.Object Parent { get => this; }
|
||||
public ILogicNode[] LogicNodes { get => m_Data?.LogicNodes; set => m_Data.LogicNodes = value as ITreeLogicNode[]; }
|
||||
public ITreeLogicNode[] TreeLogicNodes { get => m_Data?.LogicNodes; set => m_Data.LogicNodes = value; }
|
||||
public IEventNode[] EventNodes { get => m_Data?.EventNodes; set => m_Data.EventNodes = value; }
|
||||
public SharedVariable[] SharedVariables { get => m_Data?.SharedVariables; set => m_Data.SharedVariables = value; }
|
||||
public SharedVariableGroup[] SharedVariableGroups {
|
||||
#if UNITY_EDITOR
|
||||
get => Data?.SharedVariableGroups;
|
||||
set => Data.SharedVariableGroups = value;
|
||||
#else
|
||||
get => null;
|
||||
set { }
|
||||
#endif
|
||||
}
|
||||
public ushort[] DisabledLogicNodes { get => m_Data.DisabledLogicNodes; set => m_Data.DisabledLogicNodes = value; }
|
||||
public ushort[] DisabledEventNodes { get => m_Data.DisabledEventNodes; set => m_Data.DisabledEventNodes = value; }
|
||||
|
||||
public LogicNodeProperties[] LogicNodeProperties
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
get => m_Data.LogicNodeProperties;
|
||||
set => m_Data.LogicNodeProperties = value;
|
||||
#else
|
||||
get => null;
|
||||
set { }
|
||||
#endif
|
||||
}
|
||||
public NodeProperties[] EventNodeProperties
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
get => m_Data.EventNodeProperties;
|
||||
set => m_Data.EventNodeProperties = value;
|
||||
#else
|
||||
get => null;
|
||||
set { }
|
||||
#endif
|
||||
}
|
||||
public GroupProperties[] GroupProperties
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
get => m_Data.GroupProperties;
|
||||
set => m_Data.GroupProperties = value;
|
||||
#else
|
||||
get => null;
|
||||
set { }
|
||||
#endif
|
||||
}
|
||||
|
||||
public int UniqueID { get => m_Data.UniqueID; }
|
||||
public bool Pooled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the behavior tree.
|
||||
/// </summary>
|
||||
public void Serialize()
|
||||
{
|
||||
m_Data.Serialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialize the behavior tree.
|
||||
/// </summary>
|
||||
/// <param name="force">Should the behavior tree be force deserialized?</param>
|
||||
/// <returns>True if the tree was deserialized.</returns>
|
||||
public bool Deserialize(bool force = false)
|
||||
{
|
||||
return Deserialize(null, force, force, false, true, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialize the behavior tree.
|
||||
/// </summary>
|
||||
/// <param name="force">Should the behavior tree be force deserialized?</param>
|
||||
/// <param name="forceSharedVariables">Should the shared variables be force deserialized?</param>
|
||||
/// <param name="injectSubtrees">Should the subtrees be injected into the behavior tree?</param>
|
||||
/// <param name="canDeepCopyVariables">Can the SharedVariables be deep copied?</param>
|
||||
/// <returns>True if the tree was deserialized.</returns>
|
||||
public bool Deserialize(bool force, bool forceSharedVariables, bool injectSubtrees, bool canDeepCopyVariables = true)
|
||||
{
|
||||
return Deserialize(null, force, forceSharedVariables, injectSubtrees, canDeepCopyVariables, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialize the behavior tree.
|
||||
/// </summary>
|
||||
/// <param name="graphComponent">The component that the graph is being deserialized from.</param>
|
||||
/// <param name="force">Should the behavior tree be force deserialized?</param>
|
||||
/// <param name="forceSharedVariables">Should the shared variables be force deserialized?</param>
|
||||
/// <param name="injectSubtrees">Should the subtrees be injected into the behavior tree?</param>
|
||||
/// <param name="canDeepCopyVariables">Can the SharedVariables be deep copied?</param>
|
||||
/// <param name="sharedVariableOverrides">A list of SharedVariables that should override the current SharedVariable value.</param>
|
||||
/// <returns>True if the tree was deserialized.</returns>
|
||||
public bool Deserialize(IGraphComponent graphComponent, bool force, bool forceSharedVariables, bool injectSubtrees, bool canDeepCopyVariables, SharedVariableOverride[] sharedVariableOverrides)
|
||||
{
|
||||
if (m_Data == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_Data.Deserialize(graphComponent, this, force, forceSharedVariables, injectSubtrees, canDeepCopyVariables, sharedVariableOverrides);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the SharedVariables. This allows the SharedVariables to be deserialized independently.
|
||||
/// </summary>
|
||||
/// <param name="force">Should the variables be forced deserialized?</param>
|
||||
/// <returns>True if the SharedVariables were deserialized.</returns>
|
||||
public bool DeserializeSharedVariables(bool force)
|
||||
{
|
||||
if (m_Data == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_Data.DeserializeSharedVariables(this, force, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified logic node.
|
||||
/// </summary>
|
||||
/// <param name="node">The node that should be added.</param>
|
||||
public void AddNode(ILogicNode node)
|
||||
{
|
||||
m_Data.AddNode(node as ITreeLogicNode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the specified logic node.
|
||||
/// </summary>
|
||||
/// <param name="node">The node that should be removed.</param>
|
||||
/// <returns>True if the node was removed.</returns>
|
||||
public bool RemoveNode(ILogicNode node)
|
||||
{
|
||||
return m_Data.RemoveNode(node as ITreeLogicNode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified event node.
|
||||
/// </summary>
|
||||
/// <param name="eventNode">The event node that should be added.</param>
|
||||
public void AddNode(IEventNode eventNode)
|
||||
{
|
||||
m_Data.AddNode(eventNode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the specified event node.
|
||||
/// </summary>
|
||||
/// <param name="eventNode">The event node that should be removed.</param>
|
||||
/// <returns>True if the event node was removed.</returns>
|
||||
public bool RemoveNode(IEventNode eventNode)
|
||||
{
|
||||
return m_Data.RemoveNode(eventNode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Node of the specified type.
|
||||
/// </summary>
|
||||
/// <param name="type">The type of Node that should be retrieved.</typeparam>
|
||||
/// <returns>The Node of the specified type (can be null).</returns>
|
||||
public ILogicNode GetNode(Type type)
|
||||
{
|
||||
return m_Data.GetNode(type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the EventNode of the specified type.
|
||||
/// </summary>
|
||||
/// <param name="type">The type of EventNode that should be retrieved.</typeparam>
|
||||
/// <returns>The EventNode of the specified type (can be null). If the node is found the index will also be returned.</returns>
|
||||
public (IEventNode, ushort) GetEventNode(Type type)
|
||||
{
|
||||
return m_Data.GetEventNode(type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the SharedVariable with the specified name.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the SharedVariable that should be retrieved.</param>
|
||||
/// <returns>The SharedVariable with the specified name (can be null).</returns>
|
||||
public SharedVariable GetVariable(PropertyName name)
|
||||
{
|
||||
Deserialize();
|
||||
|
||||
return m_Data.GetVariable(this, name, SharedVariable.SharingScope.Graph);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the SharedVariable of the specified name.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the SharedVariable that should be retrieved.</param>
|
||||
/// <returns>The SharedVariable with the specified name (can be null).</returns>
|
||||
public SharedVariable<T> GetVariable<T>(PropertyName name)
|
||||
{
|
||||
Deserialize();
|
||||
|
||||
return m_Data.GetVariable<T>(this, name, SharedVariable.SharingScope.Graph);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value of the SharedVariable.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of SharedVarible.</typeparam>
|
||||
/// <param name="name">The name of the SharedVariable.</param>
|
||||
/// <param name="value">The value of the SharedVariable.</param>
|
||||
/// <returns>True if the value was set.</returns>
|
||||
public bool SetVariableValue<T>(PropertyName name, T value)
|
||||
{
|
||||
Deserialize();
|
||||
|
||||
return m_Data.SetVariableValue<T>(this, name, value, SharedVariable.SharingScope.Graph);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is the node with the specified index enabled?
|
||||
/// </summary>
|
||||
/// <param name="logicNode">Is the node a LogicNode?</param>
|
||||
/// <param name="index">The index of the node.</param>
|
||||
/// <returns>True if the node with the specified index is enabled.</returns>
|
||||
public bool IsNodeEnabled(bool logicNode, int index)
|
||||
{
|
||||
return m_Data.IsNodeEnabled(logicNode, index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is the node with the specified index active?
|
||||
/// </summary>
|
||||
/// <param name="logicNode">Is the node a LogicNode?</param>
|
||||
/// <param name="index">The index of the node.</param>
|
||||
/// <returns>True if the node with the specified index is active.</returns>
|
||||
public bool IsNodeActive(bool logicNode, int index)
|
||||
{
|
||||
return false; // The subtree node itself is never active.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the graph onto the current graph.
|
||||
/// </summary>
|
||||
/// <param name="other">The graph that should be copied.</param>
|
||||
public void Clone(IGraph other)
|
||||
{
|
||||
m_Data = new BehaviorTreeData();
|
||||
m_Data.EventNodes = other.EventNodes;
|
||||
m_Data.LogicNodes = other.LogicNodes as ITreeLogicNode[];
|
||||
m_Data.SharedVariables = other.SharedVariables;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
m_Data.EventNodeProperties = other.EventNodeProperties;
|
||||
m_Data.LogicNodeProperties = other.LogicNodeProperties;
|
||||
m_Data.GroupProperties = other.GroupProperties;
|
||||
#endif
|
||||
|
||||
m_Data.Serialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides ToString.
|
||||
/// </summary>
|
||||
/// <returns>The desired string value.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attribute indicating that a ReorderableList should be used for the Subtree array.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
|
||||
public class SubtreeListAttribute : System.Attribute
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
11
Packages/com.opsive.behaviordesigner/Runtime/Subtree.cs.meta
Normal file
11
Packages/com.opsive.behaviordesigner/Runtime/Subtree.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ab170e3869205449b993a35614c2084
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: e0a8f1df788b6274a9a24003859dfa7e, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a33ce2113e48ee54f946531482da6261
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,412 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Systems
|
||||
{
|
||||
using Opsive.BehaviorDesigner.Runtime.Components;
|
||||
using Opsive.BehaviorDesigner.Runtime.Groups;
|
||||
using Opsive.BehaviorDesigner.Runtime.Tasks;
|
||||
using Opsive.BehaviorDesigner.Runtime.Utility;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// System which checks for any tasks that should be reevaluated with conditional aborts. This system only marks the tasks, it does not do
|
||||
/// the actual reevaluation or interruption.
|
||||
/// </summary>
|
||||
[UpdateInGroup(typeof(BeforeTraversalSystemGroup), OrderFirst = true)]
|
||||
[DisableAutoCreation]
|
||||
public partial struct ReevaluateSystem : ISystem
|
||||
{
|
||||
private EntityQuery m_Query;
|
||||
|
||||
/// <summary>
|
||||
/// Builds the query.
|
||||
/// </summary>
|
||||
/// <param name="state">THe current SystemState.</param>
|
||||
private void OnCreate(ref SystemState state)
|
||||
{
|
||||
m_Query = SystemAPI.QueryBuilder().WithAllRW<TaskComponent>().WithAllRW<ReevaluateTaskComponent>().WithAll<BranchComponent>().WithAbsent<BakedBehaviorTree>().Build();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the ReevaluateJob.
|
||||
/// </summary>
|
||||
/// <param name="state">The current SystemState.</param>
|
||||
private void OnUpdate(ref SystemState state)
|
||||
{
|
||||
var ecb = new EntityCommandBuffer(Allocator.TempJob);
|
||||
state.Dependency = new ReevaluateJob()
|
||||
{
|
||||
EntityCommandBuffer = ecb.AsParallelWriter(),
|
||||
}.ScheduleParallel(m_Query, state.Dependency);
|
||||
|
||||
// The job must run immediately for the next systems.
|
||||
state.Dependency.Complete();
|
||||
ecb.Playback(state.EntityManager);
|
||||
ecb.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Job which checks for any tasks that should be reevaluated with conditional aborts. This job only flags the tasks, it does not do
|
||||
/// the actual reevaluation or interruption.
|
||||
/// </summary>
|
||||
[BurstCompile]
|
||||
private partial struct ReevaluateJob : IJobEntity
|
||||
{
|
||||
[Tooltip("CommandBuffer which sets the component data.")]
|
||||
public EntityCommandBuffer.ParallelWriter EntityCommandBuffer;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the job.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity that is being acted upon.</param>
|
||||
/// <param name="entityIndex">The index of the entity.</param>
|
||||
/// <param name="branchComponents">An array of branch components.</param>
|
||||
/// <param name="taskComponents">An array of task components.</param>
|
||||
/// <param name="reevaluateTaskComponents">An array of reevaluate task components.</param>
|
||||
[BurstCompile]
|
||||
public void Execute(Entity entity, [EntityIndexInQuery] int entityIndex, in DynamicBuffer<BranchComponent> branchComponents, ref DynamicBuffer<TaskComponent> taskComponents, ref DynamicBuffer<ReevaluateTaskComponent> reevaluateTaskComponents)
|
||||
{
|
||||
for (int i = 0; i < reevaluateTaskComponents.Length; ++i) {
|
||||
var reevaluateTaskComponent = reevaluateTaskComponents[i];
|
||||
// The task may not be able to reevaluate.
|
||||
var taskComponent = taskComponents[reevaluateTaskComponent.Index];
|
||||
if (!taskComponent.CanReevaluate || taskComponent.Disabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The branch may not be active.
|
||||
var branchComponent = branchComponents[taskComponent.BranchIndex];
|
||||
if (branchComponent.ActiveIndex == ushort.MaxValue) {
|
||||
if (taskComponent.Reevaluate) {
|
||||
taskComponent.Reevaluate = false;
|
||||
taskComponents[reevaluateTaskComponent.Index] = taskComponent;
|
||||
|
||||
reevaluateTaskComponent.ReevaluateStatus = ReevaluateStatus.Inactive;
|
||||
reevaluateTaskComponents[i] = reevaluateTaskComponent;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
var reevaluate = false;
|
||||
if (reevaluateTaskComponent.AbortType == ConditionalAbortType.Self || reevaluateTaskComponent.AbortType == ConditionalAbortType.Both) {
|
||||
if (branchComponent.ActiveIndex > taskComponent.Index && branchComponent.ActiveIndex <= reevaluateTaskComponent.SelfPriorityUpperIndex) {
|
||||
// Reevaluate.
|
||||
reevaluate = true;
|
||||
if (reevaluateTaskComponent.ReevaluateStatus == ReevaluateStatus.Inactive) {
|
||||
reevaluateTaskComponent.ReevaluateStatus = ReevaluateStatus.Active;
|
||||
EntityCommandBuffer.SetComponentEnabled(entityIndex, entity, reevaluateTaskComponent.ReevaluateFlagComponentType, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!reevaluate && (reevaluateTaskComponent.AbortType == ConditionalAbortType.LowerPriority || reevaluateTaskComponent.AbortType == ConditionalAbortType.Both)) {
|
||||
if (branchComponent.ActiveIndex > reevaluateTaskComponent.LowerPriorityLowerIndex && branchComponent.ActiveIndex <= reevaluateTaskComponent.LowerPriorityUpperIndex) {
|
||||
// Reevaluate.
|
||||
reevaluate = true;
|
||||
if (reevaluateTaskComponent.ReevaluateStatus == ReevaluateStatus.Inactive) {
|
||||
reevaluateTaskComponent.ReevaluateStatus = ReevaluateStatus.Active;
|
||||
EntityCommandBuffer.SetComponentEnabled(entityIndex, entity, reevaluateTaskComponent.ReevaluateFlagComponentType, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The task should no longer reevaluate.
|
||||
if (!reevaluate && (taskComponent.Reevaluate || reevaluateTaskComponent.ReevaluateStatus == ReevaluateStatus.Dirty)) {
|
||||
// The system needs to be kept active if there are other tasks with the same reevaluate tag.
|
||||
var keepSystemActive = false;
|
||||
for (int j = 0; j < reevaluateTaskComponents.Length; ++j) {
|
||||
if (i == j) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((reevaluateTaskComponents[j].ReevaluateStatus == ReevaluateStatus.Active || reevaluateTaskComponents[j].ReevaluateStatus == ReevaluateStatus.Dirty) &&
|
||||
reevaluateTaskComponent.ReevaluateFlagComponentType == reevaluateTaskComponents[j].ReevaluateFlagComponentType) {
|
||||
keepSystemActive = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!keepSystemActive) {
|
||||
EntityCommandBuffer.SetComponentEnabled(entityIndex, entity, reevaluateTaskComponent.ReevaluateFlagComponentType, false);
|
||||
}
|
||||
// The task should always disable itself.
|
||||
taskComponent.Reevaluate = false;
|
||||
reevaluateTaskComponent.ReevaluateStatus = ReevaluateStatus.Inactive;
|
||||
} else {
|
||||
// Store the current status of the task. This status will be compared after the task is reevaluated within DetermineInterruptSystem.
|
||||
reevaluateTaskComponent.OriginalStatus = taskComponent.Status;
|
||||
}
|
||||
|
||||
reevaluateTaskComponents[i] = reevaluateTaskComponent;
|
||||
|
||||
taskComponent.Reevaluate = reevaluate;
|
||||
taskComponents[reevaluateTaskComponent.Index] = taskComponent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The tasks have been reevaluated. Compare the status to determine if an interrupt should occur.
|
||||
/// </summary>
|
||||
[UpdateInGroup(typeof(InterruptSystemGroup))]
|
||||
[UpdateBefore(typeof(InterruptSystem))]
|
||||
public partial struct ConditionalAbortsInvokerSystem : ISystem
|
||||
{
|
||||
private EntityQuery m_Query;
|
||||
|
||||
/// <summary>
|
||||
/// Builds the query.
|
||||
/// </summary>
|
||||
/// <param name="state">THe current SystemState.</param>
|
||||
private void OnCreate(ref SystemState state)
|
||||
{
|
||||
m_Query = SystemAPI.QueryBuilder().WithAllRW<BranchComponent>().WithAllRW<TaskComponent>().WithAllRW<ReevaluateTaskComponent>().WithAbsent<BakedBehaviorTree>().Build();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the jobs necessary for conditional aborts.
|
||||
/// </summary>
|
||||
/// <param name="state">The current SystemState.</param>
|
||||
[BurstCompile]
|
||||
private void OnUpdate(ref SystemState state)
|
||||
{
|
||||
var ecb = new EntityCommandBuffer(Allocator.TempJob);
|
||||
state.Dependency = new ConditionalAbortsJob()
|
||||
{
|
||||
EntityCommandBuffer = ecb.AsParallelWriter()
|
||||
}.ScheduleParallel(m_Query, state.Dependency);
|
||||
|
||||
// The jobs must be run immediately for the next systems.
|
||||
state.Dependency.Complete();
|
||||
ecb.Playback(state.EntityManager);
|
||||
ecb.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Job which checks for any tasks that should be reevaluated with conditional aborts. This job only flags the tasks, it does not do
|
||||
/// the actual reevaluation or interruption.
|
||||
/// </summary>
|
||||
[BurstCompile]
|
||||
private partial struct ConditionalAbortsJob : IJobEntity
|
||||
{
|
||||
[Tooltip("CommandBuffer which sets the component data.")]
|
||||
public EntityCommandBuffer.ParallelWriter EntityCommandBuffer;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the job.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity that is being acted upon.</param>
|
||||
/// <param name="entityIndex">The index of the entity.</param>
|
||||
/// <param name="branchComponents">An array of branch components.</param>
|
||||
/// <param name="taskComponents">An array of task components.</param>
|
||||
/// <param name="reevaluateTaskComponents">An array of reevaluate task components.</param>
|
||||
[BurstCompile]
|
||||
public void Execute(Entity entity, [EntityIndexInQuery] int entityIndex, ref DynamicBuffer<BranchComponent> branchComponents, ref DynamicBuffer<TaskComponent> taskComponents, ref DynamicBuffer<ReevaluateTaskComponent> reevaluateTaskComponents)
|
||||
{
|
||||
for (int i = 0; i < reevaluateTaskComponents.Length; ++i) {
|
||||
var reevaluateTaskComponent = reevaluateTaskComponents[i];
|
||||
var taskComponent = taskComponents[reevaluateTaskComponent.Index];
|
||||
|
||||
if (taskComponent.Reevaluate) {
|
||||
if (reevaluateTaskComponent.OriginalStatus != taskComponent.Status) {
|
||||
// The status is different. This will cause an interrupt.
|
||||
var branchComponent = branchComponents[taskComponent.BranchIndex];
|
||||
// The task with the highest priority should cause the abort.
|
||||
if (branchComponent.InterruptType == InterruptType.None || taskComponent.Index < branchComponent.InterruptIndex) {
|
||||
branchComponent.InterruptIndex = taskComponent.Index;
|
||||
branchComponent.InterruptType = InterruptType.Branch;
|
||||
branchComponents[taskComponent.BranchIndex] = branchComponent;
|
||||
} else {
|
||||
taskComponent.Status = TaskStatus.Inactive;
|
||||
}
|
||||
|
||||
taskComponent.Reevaluate = false;
|
||||
taskComponents[reevaluateTaskComponent.Index] = taskComponent;
|
||||
EntityCommandBuffer.SetComponentEnabled<InterruptFlag>(entityIndex, entity, true);
|
||||
|
||||
reevaluateTaskComponent.ReevaluateStatus = ReevaluateStatus.Dirty;
|
||||
var reevaluateTaskComponentsBuffer = reevaluateTaskComponents;
|
||||
reevaluateTaskComponentsBuffer[i] = reevaluateTaskComponent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes any interrupts.
|
||||
/// </summary>
|
||||
[UpdateInGroup(typeof(InterruptSystemGroup))]
|
||||
[UpdateAfter(typeof(ConditionalAbortsInvokerSystem))]
|
||||
public partial struct InterruptSystem : ISystem
|
||||
{
|
||||
private EntityQuery m_Query;
|
||||
|
||||
/// <summary>
|
||||
/// Builds the query.
|
||||
/// </summary>
|
||||
/// <param name="state">THe current SystemState.</param>
|
||||
private void OnCreate(ref SystemState state)
|
||||
{
|
||||
m_Query = SystemAPI.QueryBuilder().WithAllRW<BranchComponent>().WithAllRW<TaskComponent>().WithAll<InterruptFlag>().Build();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the InterruptJob.
|
||||
/// </summary>
|
||||
/// <param name="state">The current SystemState.</param>
|
||||
[BurstCompile]
|
||||
private void OnUpdate(ref SystemState state)
|
||||
{
|
||||
var ecb = new EntityCommandBuffer(Allocator.TempJob);
|
||||
state.Dependency = new InterruptJob()
|
||||
{
|
||||
EntityCommandBuffer = ecb.AsParallelWriter(),
|
||||
}.ScheduleParallel(m_Query, state.Dependency);
|
||||
|
||||
// The job must run immediately for the next systems.
|
||||
state.Dependency.Complete();
|
||||
ecb.Playback(state.EntityManager);
|
||||
ecb.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triggers the interrupts.
|
||||
/// </summary>
|
||||
[BurstCompile]
|
||||
private partial struct InterruptJob : IJobEntity
|
||||
{
|
||||
[Tooltip("CommandBuffer which sets the component data.")]
|
||||
public EntityCommandBuffer.ParallelWriter EntityCommandBuffer;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the job.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity that is being acted upon.</param>
|
||||
/// <param name="entityIndex">The index of the entity.</param>
|
||||
/// <param name="branchComponents">An array of branch components.</param>
|
||||
/// <param name="taskComponents">An array of task components.</param>
|
||||
[BurstCompile]
|
||||
public void Execute(Entity entity, [EntityIndexInQuery] int entityIndex, DynamicBuffer<BranchComponent> branchComponents, DynamicBuffer<TaskComponent> taskComponents)
|
||||
{
|
||||
for (ushort i = 0; i < branchComponents.Length; ++i) {
|
||||
var branchComponent = branchComponents[i];
|
||||
if (branchComponent.InterruptType != InterruptType.None) {
|
||||
var targetTaskComponent = taskComponents[branchComponent.InterruptIndex];
|
||||
var parentIndex = targetTaskComponent.ParentIndex == ushort.MaxValue ? targetTaskComponent.Index : targetTaskComponent.ParentIndex;
|
||||
TaskStatus prevActiveNewStatus;
|
||||
if (branchComponent.InterruptType == InterruptType.Branch) {
|
||||
branchComponent.NextIndex = branchComponent.InterruptIndex;
|
||||
branchComponents[i] = branchComponent;
|
||||
|
||||
// Start the target task.
|
||||
targetTaskComponent.Status = TaskStatus.Running;
|
||||
// Set the target branch tasks to running. Any parent that uses conditional aborts should implement IInterruptResponder.
|
||||
while (parentIndex != ushort.MaxValue && taskComponents[parentIndex].Status != TaskStatus.Running) {
|
||||
var parentTaskComponent = taskComponents[parentIndex];
|
||||
parentTaskComponent.Status = TaskStatus.Running;
|
||||
taskComponents[parentIndex] = parentTaskComponent;
|
||||
parentIndex = parentTaskComponent.ParentIndex;
|
||||
}
|
||||
|
||||
prevActiveNewStatus = TaskStatus.Failure;
|
||||
} else { // InterruptType.ImmediateSuccess/Failure.
|
||||
targetTaskComponent.Status = branchComponent.InterruptType == InterruptType.ImmediateSuccess ? TaskStatus.Success : TaskStatus.Failure;
|
||||
var targetBranchComponent = branchComponents[targetTaskComponent.BranchIndex];
|
||||
targetBranchComponent.NextIndex = targetTaskComponent.ParentIndex;
|
||||
branchComponents[targetTaskComponent.BranchIndex] = targetBranchComponent;
|
||||
|
||||
prevActiveNewStatus = targetTaskComponent.Status;
|
||||
}
|
||||
|
||||
// Determine if any other branches need to be interrupted.
|
||||
for (ushort j = i; j < branchComponents.Length; ++j) {
|
||||
if (i == j || TraversalUtility.IsParent((ushort)branchComponents[j].ActiveIndex, parentIndex, ref taskComponents)) {
|
||||
AbortChildren((ushort)branchComponents[j].ActiveIndex, parentIndex, ref taskComponents, prevActiveNewStatus);
|
||||
|
||||
// Reset any queued children.
|
||||
var taskComponentBuffer = taskComponents;
|
||||
var childCount = TraversalUtility.GetChildCount(branchComponent.ActiveIndex, ref taskComponentBuffer);
|
||||
for (int k = 0; k < childCount; ++k) {
|
||||
var childTaskComponent = taskComponents[branchComponent.ActiveIndex + k + 1];
|
||||
if (childTaskComponent.Status == TaskStatus.Queued) {
|
||||
childTaskComponent.Status = TaskStatus.Inactive;
|
||||
taskComponentBuffer[branchComponent.ActiveIndex + k + 1] = childTaskComponent;
|
||||
}
|
||||
}
|
||||
|
||||
// If the branch is a parallel branch then reset the NextIndex. The current branch (i) will be interrupted normally above.
|
||||
var localBranchComponent = branchComponents[j];
|
||||
if (localBranchComponent.InterruptType == InterruptType.None) {
|
||||
localBranchComponent.NextIndex = ushort.MaxValue;
|
||||
branchComponents[j] = localBranchComponent;
|
||||
}
|
||||
EntityCommandBuffer.SetComponentEnabled<InterruptedFlag>(entityIndex, entity, true);
|
||||
}
|
||||
}
|
||||
|
||||
taskComponents[targetTaskComponent.Index] = targetTaskComponent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aborts all of the children within the specified branch.
|
||||
/// </summary>
|
||||
/// <param name="activeIndex">The index of the active task within the branch.</param>
|
||||
/// <param name="parentIndex">Aborts the tasks up to the specified parent index.</param>
|
||||
/// <param name="taskComponents">All of the tasks.</param>
|
||||
/// <param name="status">The abort status.</param>
|
||||
[BurstCompile]
|
||||
private void AbortChildren(ushort activeIndex, ushort parentIndex, ref DynamicBuffer<TaskComponent> taskComponents, TaskStatus status)
|
||||
{
|
||||
while (activeIndex != ushort.MaxValue && activeIndex != parentIndex) {
|
||||
var activeTask = taskComponents[activeIndex];
|
||||
activeTask.Status = status;
|
||||
taskComponents[activeIndex] = activeTask;
|
||||
activeIndex = activeTask.ParentIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleanup the interrupts after they have run.
|
||||
/// </summary>
|
||||
[UpdateInGroup(typeof(InterruptSystemGroup), OrderLast = true)]
|
||||
public partial struct InterruptCleanupSystem : ISystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Executes the system.
|
||||
/// </summary>
|
||||
/// <param name="state">The current SystemState.</param>
|
||||
[BurstCompile]
|
||||
private void OnUpdate(ref SystemState state)
|
||||
{
|
||||
foreach (var (branchComponents, entity) in
|
||||
SystemAPI.Query<DynamicBuffer<BranchComponent>>().WithAll<InterruptFlag>().WithEntityAccess()) {
|
||||
for (int i = 0; i < branchComponents.Length; ++i) {
|
||||
var branchComponent = branchComponents[i];
|
||||
if (branchComponent.InterruptType != InterruptType.None) {
|
||||
// Reset the interruption.
|
||||
branchComponent.InterruptType = InterruptType.None;
|
||||
branchComponent.InterruptIndex = 0;
|
||||
var branchComponentBuffer = branchComponents;
|
||||
branchComponentBuffer[i] = branchComponent;
|
||||
|
||||
state.EntityManager.SetComponentEnabled<InterruptFlag>(entity, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ffa99079a1d11e547943e43bd0446c86
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,176 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Systems
|
||||
{
|
||||
using Opsive.BehaviorDesigner.Runtime.Components;
|
||||
using Opsive.BehaviorDesigner.Runtime.Groups;
|
||||
using Unity.Burst;
|
||||
using Unity.Burst.Intrinsics;
|
||||
using Unity.Collections;
|
||||
using Unity.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Resets the evaluation status.
|
||||
/// </summary>
|
||||
[DisableAutoCreation]
|
||||
[UpdateInGroup(typeof(BehaviorTreeSystemGroup), OrderLast = true)]
|
||||
[BurstCompile]
|
||||
public partial struct EvaluationCleanupSystem : ISystem
|
||||
{
|
||||
private EntityQuery m_EvaluateCleanupQuery;
|
||||
private ComponentTypeHandle<EnabledFlag> m_EnabledComponentHandle;
|
||||
private ComponentTypeHandle<EvaluateFlag> m_EvaluateComponentHandle;
|
||||
private BufferTypeHandle<BranchComponent> m_BranchComponentHandle;
|
||||
|
||||
/// <summary>
|
||||
/// Creates the required objects for use within the job system.
|
||||
/// </summary>
|
||||
/// <param name="state">The current SystemState.</param>
|
||||
[BurstCompile]
|
||||
private void OnCreate(ref SystemState state)
|
||||
{
|
||||
m_EvaluateCleanupQuery = new EntityQueryBuilder(Allocator.Temp)
|
||||
.WithAll<EvaluateFlag>()
|
||||
.WithAllRW<BranchComponent>()
|
||||
.WithOptions(EntityQueryOptions.IgnoreComponentEnabledState)
|
||||
.Build(ref state);
|
||||
m_EnabledComponentHandle = state.GetComponentTypeHandle<EnabledFlag>();
|
||||
m_EvaluateComponentHandle = state.GetComponentTypeHandle<EvaluateFlag>();
|
||||
m_BranchComponentHandle = state.GetBufferTypeHandle<BranchComponent>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the data object values for use within the job system.
|
||||
/// </summary>
|
||||
/// <param name="state">The current SystemState.</param>
|
||||
[BurstCompile]
|
||||
private void OnUpdate(ref SystemState state)
|
||||
{
|
||||
state.Dependency.Complete();
|
||||
|
||||
// Reset the evaluation status.
|
||||
m_EnabledComponentHandle.Update(ref state);
|
||||
m_EvaluateComponentHandle.Update(ref state);
|
||||
m_BranchComponentHandle.Update(ref state);
|
||||
var evaluationCleanupJob = new EvaluationCleanupJob()
|
||||
{
|
||||
EnabledComponentHandle = m_EnabledComponentHandle,
|
||||
EvaluateComponentHandle = m_EvaluateComponentHandle,
|
||||
BranchComponentHandle = m_BranchComponentHandle,
|
||||
};
|
||||
state.Dependency = evaluationCleanupJob.ScheduleParallel(m_EvaluateCleanupQuery, state.Dependency);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Job that resets the EvaluationComponent component value.
|
||||
/// </summary>
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
public struct EvaluationCleanupJob : IJobChunk
|
||||
{
|
||||
[UnityEngine.Tooltip("A reference to the Enabled Component Handle.")]
|
||||
public ComponentTypeHandle<EnabledFlag> EnabledComponentHandle;
|
||||
[UnityEngine.Tooltip("A reference to the Evaluate Component Handle.")]
|
||||
public ComponentTypeHandle<EvaluateFlag> EvaluateComponentHandle;
|
||||
[UnityEngine.Tooltip("A reference to the Branch Component Handle.")]
|
||||
public BufferTypeHandle<BranchComponent> BranchComponentHandle;
|
||||
|
||||
/// <summary>
|
||||
/// Resets the EvaluationComponent component value.
|
||||
/// </summary>
|
||||
/// <param name="chunk">Block of memory that contains the entity and components.</param>
|
||||
/// <param name="unfilteredChunkIndex">The index of the chunk.</param>
|
||||
/// <param name="useEnabledMask">Should the enabled mask be used?</param>
|
||||
/// <param name="chunkEnabledMask">The bitwise enabled mask.</param>
|
||||
[BurstCompile]
|
||||
public void Execute(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask)
|
||||
{
|
||||
var branchAccessor = chunk.GetBufferAccessor(ref BranchComponentHandle);
|
||||
for (int i = 0; i < chunk.Count; i++) {
|
||||
// If the chunk is enabled then it should be evaluated.
|
||||
if (chunk.IsComponentEnabled<EnabledFlag>(ref EnabledComponentHandle, i)) {
|
||||
chunk.SetComponentEnabled<EvaluateFlag>(ref EvaluateComponentHandle, i, true);
|
||||
}
|
||||
|
||||
// Reset CanExecute for all branches so they can execute in the next tick.
|
||||
var branchComponents = branchAccessor[i];
|
||||
for (int j = 0; j < branchComponents.Length; j++) {
|
||||
var branchComponent = branchComponents[j];
|
||||
branchComponent.CanExecute = true;
|
||||
branchComponent.LastActiveIndex = ushort.MaxValue;
|
||||
branchComponents[j] = branchComponent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the InterruptedFlag enabled value.
|
||||
/// </summary>
|
||||
[DisableAutoCreation]
|
||||
[UpdateInGroup(typeof(BehaviorTreeSystemGroup), OrderLast = true)]
|
||||
[BurstCompile]
|
||||
public partial struct InterruptedCleanupSystem : ISystem
|
||||
{
|
||||
private EntityQuery m_InterruptedCleanupQuery;
|
||||
private ComponentTypeHandle<InterruptedFlag> m_InterruptedComponentHandle;
|
||||
|
||||
/// <summary>
|
||||
/// Creates the required objects for use within the job system.
|
||||
/// </summary>
|
||||
/// <param name="state">The current SystemState.</param>
|
||||
[BurstCompile]
|
||||
private void OnCreate(ref SystemState state)
|
||||
{
|
||||
m_InterruptedCleanupQuery = new EntityQueryBuilder(Allocator.Temp)
|
||||
.WithAll<InterruptedFlag>()
|
||||
.Build(ref state);
|
||||
m_InterruptedComponentHandle = state.GetComponentTypeHandle<InterruptedFlag>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the data object values for use within the job system.
|
||||
/// </summary>
|
||||
/// <param name="state">The current SystemState.</param>
|
||||
[BurstCompile]
|
||||
private void OnUpdate(ref SystemState state)
|
||||
{
|
||||
// Clean up the interrupted tag.
|
||||
m_InterruptedComponentHandle.Update(ref state);
|
||||
var interruptedJob = new InterruptedCleanupJob()
|
||||
{
|
||||
InterruptedComponentHandle = m_InterruptedComponentHandle,
|
||||
};
|
||||
state.Dependency = interruptedJob.ScheduleParallel(m_InterruptedCleanupQuery, state.Dependency);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Job that resets the InterruptedFlag value.
|
||||
/// </summary>
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
public partial struct InterruptedCleanupJob : IJobChunk
|
||||
{
|
||||
[UnityEngine.Tooltip("A reference to the Interrupted Component Handle.")]
|
||||
public ComponentTypeHandle<InterruptedFlag> InterruptedComponentHandle;
|
||||
|
||||
/// <summary>
|
||||
/// Resets the InterruptedFlag value.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity that is being acted upon.</param>
|
||||
/// <param name="entityIndex">The index of the entity.</param>
|
||||
[BurstCompile]
|
||||
public void Execute(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask)
|
||||
{
|
||||
for (int i = 0; i < chunk.Count; i++) {
|
||||
// Only chunks with the tag enabled will be returned so there's no need to check if the tag is enabled.
|
||||
chunk.SetComponentEnabled<InterruptedFlag>(ref InterruptedComponentHandle, i, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 36ac1accbf78b7344be0384fd1edf942
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,217 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Systems
|
||||
{
|
||||
using Opsive.BehaviorDesigner.Runtime.Components;
|
||||
using Opsive.BehaviorDesigner.Runtime.Groups;
|
||||
using Opsive.BehaviorDesigner.Runtime.Tasks;
|
||||
using Opsive.BehaviorDesigner.Runtime.Utility;
|
||||
using Opsive.GraphDesigner.Runtime;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies that the node is an object task which can specify the next child that should run.
|
||||
/// </summary>
|
||||
public interface ITaskObjectParentNode
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the index of the next child that should run. Set to ushort.MaxValue to ignore.
|
||||
/// </summary>
|
||||
ushort NextChildIndex { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The DOTS data structure for the TaskObject class.
|
||||
/// </summary>
|
||||
public struct TaskObjectComponent : IBufferElementData
|
||||
{
|
||||
[Tooltip("The index of the task.")]
|
||||
public ushort Index;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A DOTS flag indicating when an TaskObject node is active.
|
||||
/// </summary>
|
||||
public struct TaskObjectFlag : IComponentData, IEnableableComponent { }
|
||||
|
||||
/// <summary>
|
||||
/// Runs the TaskObject logic.
|
||||
/// </summary>
|
||||
[DisableAutoCreation]
|
||||
[UpdateInGroup(typeof(TraversalTaskSystemGroup), OrderLast = true)]
|
||||
public partial struct TaskObjectSystem : ISystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Updates the logic.
|
||||
/// </summary>
|
||||
/// <param name="state">The current state of the system.</param>
|
||||
private void OnUpdate(ref SystemState state)
|
||||
{
|
||||
// When the task is interrupted there is no callback which prevents Task.OnEnd from being called. Track the status within the referenced task object and if the status is different then
|
||||
// the task was aborted and OnEnd needs to be called.
|
||||
foreach (var (taskObjectComponents, taskComponents, entity) in
|
||||
SystemAPI.Query<DynamicBuffer<TaskObjectComponent>, DynamicBuffer<TaskComponent>>().WithAll<InterruptedFlag>().WithEntityAccess()) {
|
||||
var behaviorTree = BehaviorTree.GetBehaviorTree(entity);
|
||||
if (behaviorTree == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < taskObjectComponents.Length; ++i) {
|
||||
var taskObjectComponent = taskObjectComponents[i];
|
||||
var taskComponent = taskComponents[taskObjectComponent.Index];
|
||||
if (taskComponent.Status == TaskStatus.Success || taskComponent.Status == TaskStatus.Failure) {
|
||||
var task = behaviorTree.GetTask(taskObjectComponent.Index) as Task;
|
||||
if (task.Status != taskComponent.Status) {
|
||||
task.OnEnd();
|
||||
task.Status = taskComponent.Status;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the task objects.
|
||||
foreach (var (taskObjectComponents, taskComponents, branchComponents, entity) in
|
||||
SystemAPI.Query<DynamicBuffer<TaskObjectComponent>, DynamicBuffer<TaskComponent>, DynamicBuffer<BranchComponent>>().WithAll<TaskObjectFlag, EvaluateFlag>().WithEntityAccess()) {
|
||||
|
||||
var behaviorTree = BehaviorTree.GetBehaviorTree(entity);
|
||||
if (behaviorTree == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < taskObjectComponents.Length; ++i) {
|
||||
var taskObjectComponent = taskObjectComponents[i];
|
||||
var taskComponent = taskComponents[taskObjectComponent.Index];
|
||||
var branchComponent = branchComponents[taskComponent.BranchIndex];
|
||||
if (!branchComponent.CanExecute || branchComponent.ActiveIndex != taskComponent.Index) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var task = behaviorTree.GetTask(taskObjectComponent.Index) as Task;
|
||||
if (taskComponent.Status == TaskStatus.Queued) {
|
||||
task.Status = taskComponent.Status = TaskStatus.Running;
|
||||
var taskComponentBuffer = taskComponents;
|
||||
taskComponentBuffer[taskComponent.Index] = taskComponent;
|
||||
|
||||
task.OnStart();
|
||||
}
|
||||
if (taskComponent.Status != TaskStatus.Running) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var status = task.OnUpdate();
|
||||
// Update the status if has changed.
|
||||
if (status != taskComponent.Status) {
|
||||
task.Status = taskComponent.Status = status;
|
||||
var taskComponentBuffer = taskComponents;
|
||||
taskComponentBuffer[taskComponent.Index] = taskComponent;
|
||||
|
||||
// End the task if it is done running.
|
||||
if (status != TaskStatus.Running) {
|
||||
task.OnEnd();
|
||||
|
||||
branchComponent = branchComponents[taskComponent.BranchIndex];
|
||||
branchComponent.NextIndex = taskComponent.ParentIndex;
|
||||
var branchComponentBuffer = branchComponents;
|
||||
branchComponentBuffer[taskComponent.BranchIndex] = branchComponent;
|
||||
}
|
||||
}
|
||||
|
||||
if (task is IParentNode && (task is ITaskObjectParentNode taskObjectParentNode)) {
|
||||
if (status == TaskStatus.Running) {
|
||||
// Parent object tasks do not have a direct way to set the next child. Use the ITaskObjectParentNode to switch the child task.
|
||||
if (taskObjectParentNode.NextChildIndex != ushort.MaxValue && taskComponents[taskObjectParentNode.NextChildIndex].Status != TaskStatus.Running) {
|
||||
branchComponent = branchComponents[taskComponent.BranchIndex];
|
||||
branchComponent.NextIndex = taskObjectParentNode.NextChildIndex;
|
||||
var branchComponentBuffer = branchComponents;
|
||||
branchComponentBuffer[taskComponent.BranchIndex] = branchComponent;
|
||||
|
||||
var nextTaskComponent = taskComponents[taskObjectParentNode.NextChildIndex];
|
||||
nextTaskComponent.Status = TaskStatus.Queued;
|
||||
var taskComponentBuffer = taskComponents;
|
||||
taskComponentBuffer[taskObjectParentNode.NextChildIndex] = nextTaskComponent;
|
||||
}
|
||||
} else if (status == TaskStatus.Success || status == TaskStatus.Failure) {
|
||||
// An interrupt should occur if the parent returns a success or failure status before the children.
|
||||
var taskComponentBuffer = taskComponents;
|
||||
var childCount = TraversalUtility.GetChildCount(taskComponent.Index, ref taskComponentBuffer);
|
||||
var branchComponentBuffer = branchComponents;
|
||||
var hasInterruptComponents = SystemAPI.HasComponent<InterruptFlag>(entity);
|
||||
var interruptedFlagEnabled = SystemAPI.IsComponentEnabled<InterruptedFlag>(entity);
|
||||
for (ushort j = (ushort)(taskComponent.Index + 1); j < taskComponent.Index + 1 + childCount; ++j) {
|
||||
var childTaskComponent = taskComponentBuffer[j];
|
||||
if (childTaskComponent.Status == TaskStatus.Running || childTaskComponent.Status == TaskStatus.Queued) {
|
||||
childTaskComponent.Status = status;
|
||||
taskComponentBuffer[j] = childTaskComponent;
|
||||
|
||||
branchComponent = branchComponentBuffer[childTaskComponent.BranchIndex];
|
||||
if (!hasInterruptComponents) {
|
||||
ComponentUtility.AddInterruptComponents(behaviorTree.World.EntityManager, entity);
|
||||
hasInterruptComponents = true;
|
||||
}
|
||||
if (!interruptedFlagEnabled) {
|
||||
SystemAPI.SetComponentEnabled<InterruptedFlag>(entity, true);
|
||||
interruptedFlagEnabled = true;
|
||||
}
|
||||
if (branchComponent.ActiveIndex == childTaskComponent.Index) {
|
||||
branchComponent.NextIndex = ushort.MaxValue;
|
||||
branchComponentBuffer[childTaskComponent.BranchIndex] = branchComponent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A DOTS tag indicating when an TaskObject node needs to be reevaluated.
|
||||
/// </summary>
|
||||
public struct TaskObjectReevaluateFlag : IComponentData, IEnableableComponent
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the TaskObject reevaluation logic.
|
||||
/// </summary>
|
||||
[DisableAutoCreation]
|
||||
public partial struct TaskObjectReevaluateSystem : ISystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Updates the reevaluation logic.
|
||||
/// </summary>
|
||||
/// <param name="state">The current state of the system.</param>
|
||||
private void OnUpdate(ref SystemState state)
|
||||
{
|
||||
foreach (var (taskComponents, taskObjectComponents, entity) in
|
||||
SystemAPI.Query<DynamicBuffer<TaskComponent>, DynamicBuffer<TaskObjectComponent>>().WithAll<TaskObjectReevaluateFlag, EvaluateFlag>().WithEntityAccess()) {
|
||||
for (int i = 0; i < taskObjectComponents.Length; ++i) {
|
||||
var taskObjectComponent = taskObjectComponents[i];
|
||||
var taskComponent = taskComponents[taskObjectComponent.Index];
|
||||
if (!taskComponent.Reevaluate) {
|
||||
continue;
|
||||
}
|
||||
var behaviorTree = BehaviorTree.GetBehaviorTree(entity);
|
||||
if (behaviorTree == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var task = behaviorTree.GetTask(taskObjectComponent.Index) as IConditionalReevaluation;
|
||||
var status = task.OnReevaluateUpdate();
|
||||
if (status != taskComponent.Status) {
|
||||
taskComponent.Status = status;
|
||||
var buffer = taskComponents;
|
||||
buffer[taskComponent.Index] = taskComponent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 203f2349f12650c4f887e6a0a3925c04
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,617 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Systems
|
||||
{
|
||||
using Opsive.BehaviorDesigner.Runtime.Components;
|
||||
using Opsive.BehaviorDesigner.Runtime.Groups;
|
||||
using Opsive.BehaviorDesigner.Runtime.Tasks;
|
||||
using Opsive.BehaviorDesigner.Runtime.Utility;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Entities;
|
||||
using Unity.Jobs;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Traverses and ensures the correct tasks are active.
|
||||
/// </summary>
|
||||
[UpdateInGroup(typeof(TraversalSystemGroup))]
|
||||
[UpdateAfter(typeof(TraversalTaskSystemGroup))]
|
||||
public partial struct EvaluationSystem : ISystem
|
||||
{
|
||||
private bool m_JobScheduled;
|
||||
private EntityQuery m_Query;
|
||||
private JobHandle m_Dependency;
|
||||
private EntityCommandBuffer m_EntityCommandBuffer;
|
||||
|
||||
/// <summary>
|
||||
/// The system has been created.
|
||||
/// </summary>
|
||||
/// <param name="state">The state of the system.</param>
|
||||
private void OnCreate(ref SystemState state)
|
||||
{
|
||||
m_JobScheduled = false;
|
||||
m_Query = SystemAPI.QueryBuilder().WithAllRW<BranchComponent, TaskComponent>().WithAbsent<BakedBehaviorTree>().Build();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the job which traverses the tree.
|
||||
/// </summary>
|
||||
/// <param name="state">The current state of the system.</param>
|
||||
private void OnUpdate(ref SystemState state)
|
||||
{
|
||||
m_JobScheduled = true;
|
||||
|
||||
m_EntityCommandBuffer = new EntityCommandBuffer(state.WorldUpdateAllocator);
|
||||
m_Dependency = state.Dependency = new EvaluationJob()
|
||||
{
|
||||
EntityCommandBuffer = m_EntityCommandBuffer.AsParallelWriter(),
|
||||
}.ScheduleParallel(m_Query, state.Dependency);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Completes the job and releases any memory.
|
||||
/// </summary>
|
||||
/// <param name="entityManager">The running EntityManager.</param>
|
||||
/// <param name="stopRunning">Has the system been stopped?</param>
|
||||
[BurstCompile]
|
||||
public void Complete(EntityManager entityManager, bool stopRunning = false)
|
||||
{
|
||||
if (!m_JobScheduled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!stopRunning) {
|
||||
m_Dependency.Complete();
|
||||
m_EntityCommandBuffer.Playback(entityManager);
|
||||
m_EntityCommandBuffer.Dispose();
|
||||
}
|
||||
|
||||
m_JobScheduled = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Job which traverses the tree.
|
||||
/// </summary>
|
||||
[BurstCompile]
|
||||
public partial struct EvaluationJob : IJobEntity
|
||||
{
|
||||
[Tooltip("CommandBuffer which sets the component data.")]
|
||||
public EntityCommandBuffer.ParallelWriter EntityCommandBuffer;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the job.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity that is being acted upon.</param>
|
||||
/// <param name="entityIndex">The index of the entity.</param
|
||||
/// <param name="branchComponents">An array of branch components.</param>
|
||||
/// <param name="taskComponents">An array of task components.</param>
|
||||
[BurstCompile]
|
||||
public void Execute(Entity entity, [EntityIndexInQuery] int entityIndex, ref DynamicBuffer<BranchComponent> branchComponents, ref DynamicBuffer<TaskComponent> taskComponents)
|
||||
{
|
||||
for (int i = 0; i < branchComponents.Length; ++i) {
|
||||
var branchComponent = branchComponents[i];
|
||||
if (branchComponent.ActiveIndex != ushort.MaxValue && branchComponent.ActiveIndex == branchComponent.NextIndex) {
|
||||
var activeTask = taskComponents[branchComponent.ActiveIndex];
|
||||
if (activeTask.Status == TaskStatus.Success || activeTask.Status == TaskStatus.Failure) {
|
||||
branchComponent.NextIndex = activeTask.ParentIndex;
|
||||
}
|
||||
}
|
||||
if (branchComponent.ActiveIndex != branchComponent.NextIndex) {
|
||||
// Do not switch into a disabled task.
|
||||
if (branchComponent.NextIndex != ushort.MaxValue && taskComponents[branchComponent.NextIndex].Disabled) {
|
||||
var taskComponent = taskComponents[branchComponent.NextIndex];
|
||||
taskComponent.Status = TaskStatus.Inactive;
|
||||
var taskComponentBuffer = taskComponents;
|
||||
taskComponentBuffer[branchComponent.NextIndex] = taskComponent;
|
||||
|
||||
branchComponent.NextIndex = branchComponent.ActiveIndex;
|
||||
} else {
|
||||
// The status for all children should be reset back to their inactive state if the next task is within a new branch. This will prevent
|
||||
// the return status from being reset when the task ends normally.
|
||||
var taskComponentBuffer = taskComponents;
|
||||
if (branchComponent.NextIndex != ushort.MaxValue &&
|
||||
!TraversalUtility.IsParent((ushort)branchComponent.ActiveIndex, (ushort)branchComponent.NextIndex, ref taskComponentBuffer)) {
|
||||
var nextTaskComponent = taskComponents[branchComponent.NextIndex];
|
||||
if (branchComponent.ActiveIndex != ushort.MaxValue && nextTaskComponent.Status != TaskStatus.Running) { // If the next task is already running then an interrupt has already reset the children.
|
||||
var childCount = TraversalUtility.GetChildCount(branchComponent.NextIndex, ref taskComponentBuffer);
|
||||
for (int j = 0; j < childCount; ++j) {
|
||||
var childTaskComponent = taskComponents[branchComponent.NextIndex + j + 1];
|
||||
childTaskComponent.Status = TaskStatus.Inactive;
|
||||
taskComponentBuffer[branchComponent.NextIndex + j + 1] = childTaskComponent;
|
||||
}
|
||||
}
|
||||
nextTaskComponent.Status = nextTaskComponent.Status == TaskStatus.Running ? TaskStatus.Running : TaskStatus.Queued;
|
||||
taskComponentBuffer[branchComponent.NextIndex] = nextTaskComponent;
|
||||
}
|
||||
branchComponent.ActiveIndex = branchComponent.NextIndex;
|
||||
|
||||
// Change the component tag if the task type is different.
|
||||
var componentType = branchComponent.ActiveIndex != ushort.MaxValue ? taskComponents[branchComponent.ActiveIndex].FlagComponentType : new ComponentType();
|
||||
if (componentType != branchComponent.ActiveFlagComponentType) {
|
||||
if (branchComponent.ActiveFlagComponentType.TypeIndex != TypeIndex.Null) {
|
||||
var deactivateTag = true;
|
||||
for (int j = 0; j < branchComponents.Length; ++j) {
|
||||
// The tag should be deactivated if no other tasks have the same tag type.
|
||||
if (i != j && branchComponents[j].ActiveIndex != ushort.MaxValue &&
|
||||
branchComponent.ActiveFlagComponentType == branchComponents[j].ActiveFlagComponentType) {
|
||||
deactivateTag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// The task of that type is no longer active - disable the system to prevent it from running.
|
||||
if (deactivateTag) {
|
||||
EntityCommandBuffer.SetComponentEnabled(entityIndex, entity, branchComponent.ActiveFlagComponentType, false);
|
||||
}
|
||||
}
|
||||
// A new system type should start.
|
||||
if (branchComponent.ActiveIndex != ushort.MaxValue) {
|
||||
var taskComponent = taskComponents[branchComponent.ActiveIndex];
|
||||
EntityCommandBuffer.SetComponentEnabled(entityIndex, entity, taskComponent.FlagComponentType, true);
|
||||
}
|
||||
branchComponent.ActiveFlagComponentType = componentType;
|
||||
}
|
||||
}
|
||||
var branchComponentBuffer = branchComponents;
|
||||
branchComponentBuffer[i] = branchComponent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loops through the active tasks to determine if the system should stay active for the current tick.
|
||||
/// </summary>
|
||||
[UpdateInGroup(typeof(TraversalSystemGroup))]
|
||||
[UpdateAfter(typeof(EvaluationSystem))]
|
||||
public partial struct DetermineEvaluationSystem : ISystem
|
||||
{
|
||||
[Tooltip("Should the group stay active? An inactive tree does not run.")]
|
||||
public bool Active { get; private set; }
|
||||
[Tooltip("Should the group be evaluated? This bool indicates if the entire tree should be evaluated instead of the reevaluation" +
|
||||
"concept for conditional aborts. The tree will be reevaluated if any of the leaf tasks have a status of running.")]
|
||||
public bool Evaluate { get; private set; }
|
||||
|
||||
private bool m_JobScheduled;
|
||||
private JobHandle m_Dependency;
|
||||
|
||||
private EntityQuery m_Query32;
|
||||
private EntityQuery m_Query64;
|
||||
private EntityQuery m_Query128;
|
||||
private EntityQuery m_Query512;
|
||||
private EntityQuery m_Query4096;
|
||||
private EntityCommandBuffer m_EntityCommandBuffer32;
|
||||
private EntityCommandBuffer m_EntityCommandBuffer64;
|
||||
private EntityCommandBuffer m_EntityCommandBuffer128;
|
||||
private EntityCommandBuffer m_EntityCommandBuffer512;
|
||||
private EntityCommandBuffer m_EntityCommandBuffer4096;
|
||||
|
||||
private NativeArray<bool> m_Results;
|
||||
|
||||
/// <summary>
|
||||
/// The system has been created.
|
||||
/// </summary>
|
||||
/// <param name="state">The state of the system.</param>
|
||||
private void OnCreate(ref SystemState state)
|
||||
{
|
||||
Active = Evaluate = true;
|
||||
m_JobScheduled = false;
|
||||
m_Query32 = SystemAPI.QueryBuilder().WithAllRW<BranchComponent>().WithAll<TaskComponent, EvaluationComponent32, EvaluateFlag>().WithAbsent<BakedBehaviorTree>().Build();
|
||||
m_Query64 = SystemAPI.QueryBuilder().WithAllRW<BranchComponent>().WithAll<TaskComponent, EvaluationComponent64, EvaluateFlag>().WithAbsent<BakedBehaviorTree>().Build();
|
||||
m_Query128 = SystemAPI.QueryBuilder().WithAllRW<BranchComponent>().WithAll<TaskComponent, EvaluationComponent128, EvaluateFlag>().WithAbsent<BakedBehaviorTree>().Build();
|
||||
m_Query512 = SystemAPI.QueryBuilder().WithAllRW<BranchComponent>().WithAll<TaskComponent, EvaluationComponent512, EvaluateFlag>().WithAbsent<BakedBehaviorTree>().Build();
|
||||
m_Query4096 = SystemAPI.QueryBuilder().WithAllRW<BranchComponent>().WithAll<TaskComponent, EvaluationComponent4096, EvaluateFlag>().WithAbsent<BakedBehaviorTree>().Build();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the job to determine if the system should stay active and evaluating.
|
||||
/// </summary>
|
||||
/// <param name="state">The current state of the system.</param>
|
||||
[BurstCompile]
|
||||
private void OnUpdate(ref SystemState state)
|
||||
{
|
||||
Active = Evaluate = true;
|
||||
m_JobScheduled = true;
|
||||
|
||||
m_EntityCommandBuffer32 = new EntityCommandBuffer(Allocator.TempJob);
|
||||
m_EntityCommandBuffer64 = new EntityCommandBuffer(Allocator.TempJob);
|
||||
m_EntityCommandBuffer128 = new EntityCommandBuffer(Allocator.TempJob);
|
||||
m_EntityCommandBuffer512 = new EntityCommandBuffer(Allocator.TempJob);
|
||||
m_EntityCommandBuffer4096 = new EntityCommandBuffer(Allocator.TempJob);
|
||||
|
||||
m_Results = new NativeArray<bool>(3, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
|
||||
for (int i = 0; i < m_Results.Length; ++i) {
|
||||
m_Results[i] = false;
|
||||
}
|
||||
|
||||
// Chain jobs sequentially since they all write to the shared Results array.
|
||||
m_Dependency = new DetermineEvaluationJob32()
|
||||
{
|
||||
EntityCommandBuffer = m_EntityCommandBuffer32.AsParallelWriter(),
|
||||
Results = m_Results
|
||||
}.ScheduleParallel(m_Query32, state.Dependency);
|
||||
m_Dependency = new DetermineEvaluationJob64()
|
||||
{
|
||||
EntityCommandBuffer = m_EntityCommandBuffer64.AsParallelWriter(),
|
||||
Results = m_Results
|
||||
}.ScheduleParallel(m_Query64, m_Dependency);
|
||||
m_Dependency = new DetermineEvaluationJob128()
|
||||
{
|
||||
EntityCommandBuffer = m_EntityCommandBuffer128.AsParallelWriter(),
|
||||
Results = m_Results
|
||||
}.ScheduleParallel(m_Query128, m_Dependency);
|
||||
m_Dependency = new DetermineEvaluationJob512()
|
||||
{
|
||||
EntityCommandBuffer = m_EntityCommandBuffer512.AsParallelWriter(),
|
||||
Results = m_Results
|
||||
}.ScheduleParallel(m_Query512, m_Dependency);
|
||||
m_Dependency = new DetermineEvaluationJob4096()
|
||||
{
|
||||
EntityCommandBuffer = m_EntityCommandBuffer4096.AsParallelWriter(),
|
||||
Results = m_Results
|
||||
}.ScheduleParallel(m_Query4096, m_Dependency);
|
||||
|
||||
state.Dependency = m_Dependency;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Completes the job and releases any memory.
|
||||
/// </summary>
|
||||
/// <param name="entityManager">The running EntityManager.</param>
|
||||
[BurstCompile]
|
||||
public void Complete(EntityManager entityManager)
|
||||
{
|
||||
if (!m_JobScheduled) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_Dependency.Complete();
|
||||
m_EntityCommandBuffer32.Playback(entityManager);
|
||||
m_EntityCommandBuffer32.Dispose();
|
||||
m_EntityCommandBuffer64.Playback(entityManager);
|
||||
m_EntityCommandBuffer64.Dispose();
|
||||
m_EntityCommandBuffer128.Playback(entityManager);
|
||||
m_EntityCommandBuffer128.Dispose();
|
||||
m_EntityCommandBuffer512.Playback(entityManager);
|
||||
m_EntityCommandBuffer512.Dispose();
|
||||
m_EntityCommandBuffer4096.Playback(entityManager);
|
||||
m_EntityCommandBuffer4096.Dispose();
|
||||
|
||||
if (m_Results.IsCreated) {
|
||||
if (m_Results[0]) {
|
||||
Active = m_Results[1];
|
||||
Evaluate = m_Results[2];
|
||||
} else {
|
||||
// If the first element is false then no trees executed.
|
||||
Active = Evaluate = false;
|
||||
}
|
||||
m_Results.Dispose();
|
||||
}
|
||||
m_JobScheduled = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The system has been destroyed.
|
||||
/// </summary>
|
||||
/// <param name="state">The current state of the system.</param>
|
||||
private void OnDestroy(ref SystemState state)
|
||||
{
|
||||
if (m_Dependency.IsCompleted) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_Results.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Job which determine if the system should stay active. If any behavior tree should stay active then the entire system must remain active.
|
||||
/// </summary>
|
||||
[BurstCompile]
|
||||
public partial struct DetermineEvaluationJob32 : IJobEntity
|
||||
{
|
||||
[Tooltip("CommandBuffer which sets the component data.")]
|
||||
public EntityCommandBuffer.ParallelWriter EntityCommandBuffer;
|
||||
[Tooltip("The computed results.")]
|
||||
[NativeDisableParallelForRestriction] public NativeArray<bool> Results;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the job.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity that is being acted upon.</param>
|
||||
/// <param name="entityIndex">The index of the entity.</param>
|
||||
/// <param name="branchComponents">An array of branch components.</param>
|
||||
/// <param name="taskComponents">An array of task components.</param>
|
||||
/// <param name="evaluationComponent">The EvaluationComponent that belongs to the entity.</param>
|
||||
[BurstCompile]
|
||||
private void Execute(Entity entity, [EntityIndexInQuery] int entityIndex, ref DynamicBuffer<BranchComponent> branchComponents, in DynamicBuffer<TaskComponent> taskComponents, ref EvaluationComponent32 evaluationComponent)
|
||||
{
|
||||
var evaluatedTasks = evaluationComponent.EvaluatedTasks;
|
||||
EvaluationUtility.DetermineEvaluation(entity, entityIndex, ref branchComponents, taskComponents, ref evaluatedTasks, evaluationComponent.EvaluationType, evaluationComponent.MaxEvaluationCount, EntityCommandBuffer, Results);
|
||||
evaluationComponent.EvaluatedTasks = evaluatedTasks;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Job which determine if the system should stay active. If any behavior tree should stay active then the entire system must remain active.
|
||||
/// </summary>
|
||||
[BurstCompile]
|
||||
public partial struct DetermineEvaluationJob64 : IJobEntity
|
||||
{
|
||||
[Tooltip("CommandBuffer which sets the component data.")]
|
||||
public EntityCommandBuffer.ParallelWriter EntityCommandBuffer;
|
||||
[Tooltip("The computed results.")]
|
||||
[NativeDisableParallelForRestriction] public NativeArray<bool> Results;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the job.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity that is being acted upon.</param>
|
||||
/// <param name="entityIndex">The index of the entity.</param>
|
||||
/// <param name="branchComponents">An array of branch components.</param>
|
||||
/// <param name="taskComponents">An array of task components.</param>
|
||||
/// <param name="evaluationComponent">The EvaluationComponent that belongs to the entity.</param>
|
||||
[BurstCompile]
|
||||
private void Execute(Entity entity, [EntityIndexInQuery] int entityIndex, ref DynamicBuffer<BranchComponent> branchComponents, in DynamicBuffer<TaskComponent> taskComponents, ref EvaluationComponent64 evaluationComponent)
|
||||
{
|
||||
var evaluatedTasks = evaluationComponent.EvaluatedTasks;
|
||||
EvaluationUtility.DetermineEvaluation(entity, entityIndex, ref branchComponents, taskComponents, ref evaluatedTasks, evaluationComponent.EvaluationType, evaluationComponent.MaxEvaluationCount, EntityCommandBuffer, Results);
|
||||
evaluationComponent.EvaluatedTasks = evaluatedTasks;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Job which determine if the system should stay active. If any behavior tree should stay active then the entire system must remain active.
|
||||
/// </summary>
|
||||
[BurstCompile]
|
||||
public partial struct DetermineEvaluationJob128 : IJobEntity
|
||||
{
|
||||
[Tooltip("CommandBuffer which sets the component data.")]
|
||||
public EntityCommandBuffer.ParallelWriter EntityCommandBuffer;
|
||||
[Tooltip("The computed results.")]
|
||||
[NativeDisableParallelForRestriction] public NativeArray<bool> Results;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the job.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity that is being acted upon.</param>
|
||||
/// <param name="entityIndex">The index of the entity.</param>
|
||||
/// <param name="branchComponents">An array of branch components.</param>
|
||||
/// <param name="taskComponents">An array of task components.</param>
|
||||
/// <param name="evaluationComponent">The EvaluationComponent that belongs to the entity.</param>
|
||||
[BurstCompile]
|
||||
private void Execute(Entity entity, [EntityIndexInQuery] int entityIndex, ref DynamicBuffer<BranchComponent> branchComponents, in DynamicBuffer<TaskComponent> taskComponents, ref EvaluationComponent128 evaluationComponent)
|
||||
{
|
||||
var evaluatedTasks = evaluationComponent.EvaluatedTasks;
|
||||
EvaluationUtility.DetermineEvaluation(entity, entityIndex, ref branchComponents, taskComponents, ref evaluatedTasks, evaluationComponent.EvaluationType, evaluationComponent.MaxEvaluationCount, EntityCommandBuffer, Results);
|
||||
evaluationComponent.EvaluatedTasks = evaluatedTasks;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Job which determine if the system should stay active. If any behavior tree should stay active then the entire system must remain active.
|
||||
/// </summary>
|
||||
[BurstCompile]
|
||||
public partial struct DetermineEvaluationJob512 : IJobEntity
|
||||
{
|
||||
[Tooltip("CommandBuffer which sets the component data.")]
|
||||
public EntityCommandBuffer.ParallelWriter EntityCommandBuffer;
|
||||
[Tooltip("The computed results.")]
|
||||
[NativeDisableParallelForRestriction] public NativeArray<bool> Results;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the job.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity that is being acted upon.</param>
|
||||
/// <param name="entityIndex">The index of the entity.</param>
|
||||
/// <param name="branchComponents">An array of branch components.</param>
|
||||
/// <param name="taskComponents">An array of task components.</param>
|
||||
/// <param name="evaluationComponent">The EvaluationComponent that belongs to the entity.</param>
|
||||
[BurstCompile]
|
||||
private void Execute(Entity entity, [EntityIndexInQuery] int entityIndex, ref DynamicBuffer<BranchComponent> branchComponents, in DynamicBuffer<TaskComponent> taskComponents, ref EvaluationComponent512 evaluationComponent)
|
||||
{
|
||||
var evaluatedTasks = evaluationComponent.EvaluatedTasks;
|
||||
EvaluationUtility.DetermineEvaluation(entity, entityIndex, ref branchComponents, taskComponents, ref evaluatedTasks, evaluationComponent.EvaluationType, evaluationComponent.MaxEvaluationCount, EntityCommandBuffer, Results);
|
||||
evaluationComponent.EvaluatedTasks = evaluatedTasks;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Job which determine if the system should stay active. If any behavior tree should stay active then the entire system must remain active.
|
||||
/// </summary>
|
||||
[BurstCompile]
|
||||
public partial struct DetermineEvaluationJob4096 : IJobEntity
|
||||
{
|
||||
[Tooltip("CommandBuffer which sets the component data.")]
|
||||
public EntityCommandBuffer.ParallelWriter EntityCommandBuffer;
|
||||
[Tooltip("The computed results.")]
|
||||
[NativeDisableParallelForRestriction] public NativeArray<bool> Results;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the job.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity that is being acted upon.</param>
|
||||
/// <param name="entityIndex">The index of the entity.</param>
|
||||
/// <param name="branchComponents">An array of branch components.</param>
|
||||
/// <param name="taskComponents">An array of task components.</param>
|
||||
/// <param name="evaluationComponent">The EvaluationComponent that belongs to the entity.</param>
|
||||
[BurstCompile]
|
||||
private void Execute(Entity entity, [EntityIndexInQuery] int entityIndex, ref DynamicBuffer<BranchComponent> branchComponents, in DynamicBuffer<TaskComponent> taskComponents, ref EvaluationComponent4096 evaluationComponent)
|
||||
{
|
||||
var evaluatedTasks = evaluationComponent.EvaluatedTasks;
|
||||
EvaluationUtility.DetermineEvaluation(entity, entityIndex, ref branchComponents, taskComponents, ref evaluatedTasks, evaluationComponent.EvaluationType, evaluationComponent.MaxEvaluationCount, EntityCommandBuffer, Results);
|
||||
evaluationComponent.EvaluatedTasks = evaluatedTasks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Utility functions for the task evaluation.
|
||||
/// </summary>
|
||||
[BurstCompile]
|
||||
public struct EvaluationUtility
|
||||
{
|
||||
/// <summary>
|
||||
/// Is the task at the specified index a parent task.
|
||||
/// </summary>
|
||||
/// <param name="taskComponents">An array of task components.</param>
|
||||
/// <param name="index">The index to check if it is a parent.</param>
|
||||
/// <returns>True if the task at the specified index is a parent task.</returns>
|
||||
[BurstCompile]
|
||||
public static bool IsParentTask(ref DynamicBuffer<TaskComponent> taskComponents, int index)
|
||||
{
|
||||
// The last task cannot be a parent.
|
||||
if (index == taskComponents.Length - 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The next child will have a parent of the current task.
|
||||
if (taskComponents[index + 1].ParentIndex == index) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// The parent index is different - the current task is not a parent.
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Core evaluation logic that works with any FixedList type for EvaluatedTasks.
|
||||
/// </summary>
|
||||
/// <typeparam name="TFixedList">The type of FixedList for EvaluatedTasks.</typeparam>
|
||||
/// <param name="entity">The entity that is being acted upon.</param>
|
||||
/// <param name="entityIndex">The index of the entity.</param>
|
||||
/// <param name="branchComponents">An array of branch components.</param>
|
||||
/// <param name="taskComponents">An array of task components.</param>
|
||||
/// <param name="evaluatedTasks">The evaluated tasks list.</param>
|
||||
/// <param name="evaluationType">The evaluation type.</param>
|
||||
/// <param name="maxEvaluationCount">The maximum evaluation count.</param>
|
||||
/// <param name="entityCommandBuffer">The command buffer for setting component data.</param>
|
||||
/// <param name="results">The computed results array.</param>
|
||||
[BurstCompile]
|
||||
public static void DetermineEvaluation<TFixedList>(Entity entity, int entityIndex, ref DynamicBuffer<BranchComponent> branchComponents, DynamicBuffer<TaskComponent> taskComponents, ref TFixedList evaluatedTasks, EvaluationType evaluationType, ushort maxEvaluationCount, EntityCommandBuffer.ParallelWriter entityCommandBuffer, NativeArray<bool> results) where TFixedList : struct, INativeList<ulong>
|
||||
{
|
||||
results[0] = true; // The first element indicates that the job has been executed.
|
||||
|
||||
// No branches may be active.
|
||||
var active = false;
|
||||
var evaluate = false;
|
||||
var evaluatedMask = new FixedList4096Bytes<ulong>();
|
||||
for (int i = 0; i < branchComponents.Length; ++i) {
|
||||
var branchComponent = branchComponents[i];
|
||||
if (branchComponent.ActiveIndex == ushort.MaxValue || !branchComponent.CanExecute) {
|
||||
continue;
|
||||
}
|
||||
active = true;
|
||||
|
||||
// Interrupts are processed in a separate system that is run outside of the task execution system. As a result the branch should not continue to evaluate.
|
||||
if (branchComponent.InterruptType != InterruptType.None) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var taskComponent = taskComponents[branchComponent.ActiveIndex];
|
||||
var isParentTask = EvaluationUtility.IsParentTask(ref taskComponents, branchComponent.ActiveIndex);
|
||||
// The branch can evaluate if the active task is an outer node (action or conditional) and is not running OR
|
||||
// the task is an inner node (composite or decorator), is running, and is not a parallel task. Parent tasks cannot run without an active child.
|
||||
if ((!isParentTask && taskComponent.Status != TaskStatus.Running && taskComponent.ParentIndex != ushort.MaxValue) ||
|
||||
(isParentTask && (taskComponent.Status == TaskStatus.Queued || taskComponent.Status == TaskStatus.Running))) {
|
||||
|
||||
// Compute active task bit positions.
|
||||
var bitIndex = branchComponent.ActiveIndex + 1;
|
||||
var arrayIndex = bitIndex / ComponentUtility.ulongBitSize;
|
||||
var bitInUlong = bitIndex % ComponentUtility.ulongBitSize;
|
||||
while (evaluatedMask.Length <= arrayIndex) evaluatedMask.Add(0UL);
|
||||
evaluatedMask[arrayIndex] |= (1UL << bitInUlong);
|
||||
|
||||
// Prevent evaluating the same task again within the same tick.
|
||||
if (branchComponent.ActiveIndex == branchComponent.LastActiveIndex) {
|
||||
branchComponent.CanExecute = false;
|
||||
branchComponents.ElementAt(i) = branchComponent;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the task has already been evaluated this tick.
|
||||
var alreadyEvaluated = (evaluatedTasks[arrayIndex] & (1UL << bitInUlong)) != 0;
|
||||
|
||||
// Decision to evaluate:
|
||||
// - For parent tasks: always evaluate. The parent task should never be the last executing task.
|
||||
// - For non-parent tasks: evaluate if this task hasn't been evaluated yet.
|
||||
if (isParentTask || !alreadyEvaluated) {
|
||||
evaluate = true;
|
||||
branchComponent.LastActiveIndex = branchComponent.ActiveIndex;
|
||||
} else {
|
||||
branchComponent.CanExecute = false;
|
||||
}
|
||||
branchComponents.ElementAt(i) = branchComponent;
|
||||
|
||||
evaluatedTasks[arrayIndex] |= evaluatedMask[arrayIndex];
|
||||
} else {
|
||||
branchComponent.CanExecute = false;
|
||||
branchComponents.ElementAt(i) = branchComponent;
|
||||
}
|
||||
}
|
||||
|
||||
// If a branch is active then at least one task within that branch is active.
|
||||
if (active) {
|
||||
results[1] = true; // Active result.
|
||||
|
||||
if (evaluate) {
|
||||
if (evaluationType == EvaluationType.Count) {
|
||||
// Use the last element of EvaluatedTasks as the counter.
|
||||
evaluatedTasks[evaluatedTasks.Length - 1]++;
|
||||
if (evaluatedTasks[evaluatedTasks.Length - 1] >= maxEvaluationCount) {
|
||||
// Reset the counter and bitmask elements.
|
||||
for (int i = 0; i < evaluatedTasks.Length; ++i) {
|
||||
evaluatedTasks[i] = 0;
|
||||
}
|
||||
entityCommandBuffer.SetComponentEnabled<EvaluateFlag>(entityIndex, entity, false);
|
||||
// Set the bitmask for current active tasks to prevent one extra task from being executed on subsequent frames.
|
||||
SetActiveBranchBits(ref branchComponents, ref evaluatedTasks);
|
||||
} else {
|
||||
results[2] = true; // Evaluate result.
|
||||
}
|
||||
} else {
|
||||
results[2] = true; // Evaluate result - continue the loop.
|
||||
}
|
||||
} else {
|
||||
entityCommandBuffer.SetComponentEnabled<EvaluateFlag>(entityIndex, entity, false);
|
||||
// Reset the evaluated tasks bitmask.
|
||||
for (int i = 0; i < evaluatedTasks.Length; ++i) {
|
||||
evaluatedTasks[i] = 0;
|
||||
}
|
||||
// The system is going to stop evaluating this entity. It will be resumed immediately the next update. Because the DetermineEvaluationJob is run after the tasks
|
||||
// update the EvaluatedTasks value should be set to the next active task. If this value is set to 0 then one extra task will always be executed with subsequent frames.
|
||||
SetActiveBranchBits(ref branchComponents, ref evaluatedTasks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the bitmask bits for all active branches. This prevents one extra task from being executed on subsequent frames.
|
||||
/// </summary>
|
||||
/// <param name="branchComponents">An array of branch components.</param>
|
||||
/// <param name="evaluatedTasks">The evaluated tasks list to update.</param>
|
||||
[BurstCompile]
|
||||
private static void SetActiveBranchBits<TFixedList>(ref DynamicBuffer<BranchComponent> branchComponents, ref TFixedList evaluatedTasks) where TFixedList : struct, INativeList<ulong>
|
||||
{
|
||||
for (int i = 0; i < branchComponents.Length; ++i) {
|
||||
var branchComponent = branchComponents[i];
|
||||
if (branchComponent.ActiveIndex == ushort.MaxValue) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Compute active task bit positions.
|
||||
var bitIndex = branchComponent.ActiveIndex + 1;
|
||||
var arrayIndex = bitIndex / ComponentUtility.ulongBitSize;
|
||||
var bitInUlong = bitIndex % ComponentUtility.ulongBitSize;
|
||||
evaluatedTasks[arrayIndex] |= (1UL << bitInUlong);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4e38e2be36422f54fa65b67063d03366
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Packages/com.opsive.behaviordesigner/Runtime/Tasks.meta
Normal file
8
Packages/com.opsive.behaviordesigner/Runtime/Tasks.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0b7936234bfdce042b052d68dd0136f1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 72fd968959b610e4bb7994fedbaab0c9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,19 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime;
|
||||
|
||||
/// <summary>
|
||||
/// A TaskObject implementation of the Action task.
|
||||
/// </summary>
|
||||
[NodeIcon("3bbdfa553da4d554e9d74f8d88915aac", "6437308e972f99f48953f20198fd4e94")]
|
||||
public abstract class Action : Task, IAction
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 24e232a868c7a0d439cb82feeb963c8e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,31 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// A TaskObject implementation of the Action task. This class can be used when the task should not be grouped by the StackedAction task.
|
||||
/// </summary>
|
||||
[NodeIcon("3bbdfa553da4d554e9d74f8d88915aac", "6437308e972f99f48953f20198fd4e94")]
|
||||
public abstract class ActionNode : Task, ITreeLogicNode, IAction
|
||||
{
|
||||
[Tooltip("The index of the node.")]
|
||||
[SerializeField] ushort m_Index;
|
||||
[Tooltip("The parent index of the node. ushort.MaxValue indicates no parent.")]
|
||||
[SerializeField] ushort m_ParentIndex;
|
||||
[Tooltip("The sibling index of the node. ushort.MaxValue indicates no sibling.")]
|
||||
[SerializeField] ushort m_SiblingIndex;
|
||||
|
||||
public ushort Index { get => m_Index; set => m_Index = value; }
|
||||
public ushort ParentIndex { get => m_ParentIndex; set => m_ParentIndex = value; }
|
||||
public ushort SiblingIndex { get => m_SiblingIndex; set => m_SiblingIndex = value; }
|
||||
public ushort RuntimeIndex { get; set; }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f95ceadf4eaf7df499091158c2ba5178
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a57b0c8b5bd7c5142963151eb3723e6e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,33 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using UnityEngine;
|
||||
|
||||
[Opsive.Shared.Utility.Description("Converts a boolean value to a float value (true = 1.0, false = 0.0).")]
|
||||
[Shared.Utility.Category("Conversions")]
|
||||
public class ConvertBoolToFloat : Action
|
||||
{
|
||||
[Tooltip("The boolean value to convert.")]
|
||||
[SerializeField] protected SharedVariable<bool> m_Value;
|
||||
[Tooltip("The variable that should be set to the converted float value.")]
|
||||
[RequireShared] [SerializeField] protected SharedVariable<float> m_StoreResult;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
m_StoreResult.Value = m_Value.Value ? 1.0f : 0.0f;
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 73c605544c0648e4bbf8dcfe72348337
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,33 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using UnityEngine;
|
||||
|
||||
[Opsive.Shared.Utility.Description("Converts a boolean value to an integer value (true = 1, false = 0).")]
|
||||
[Shared.Utility.Category("Conversions")]
|
||||
public class ConvertBoolToInt : Action
|
||||
{
|
||||
[Tooltip("The boolean value to convert.")]
|
||||
[SerializeField] protected SharedVariable<bool> m_Value;
|
||||
[Tooltip("The variable that should be set to the converted integer value.")]
|
||||
[RequireShared] [SerializeField] protected SharedVariable<int> m_StoreResult;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
m_StoreResult.Value = m_Value.Value ? 1 : 0;
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3955564edbd009346b730327375e3d48
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,33 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using UnityEngine;
|
||||
|
||||
[Opsive.Shared.Utility.Description("Converts a boolean value to a string value.")]
|
||||
[Shared.Utility.Category("Conversions")]
|
||||
public class ConvertBoolToString : Action
|
||||
{
|
||||
[Tooltip("The boolean value to convert.")]
|
||||
[SerializeField] protected SharedVariable<bool> m_Value;
|
||||
[Tooltip("The variable that should be set to the converted string value.")]
|
||||
[RequireShared] [SerializeField] protected SharedVariable<string> m_StoreResult;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
m_StoreResult.Value = m_Value.Value.ToString();
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 888e5ecfd2f882346ad4879020c18283
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,33 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using UnityEngine;
|
||||
|
||||
[Opsive.Shared.Utility.Description("Converts a float value to a boolean value (0.0 = false, non-zero = true).")]
|
||||
[Shared.Utility.Category("Conversions")]
|
||||
public class ConvertFloatToBool : Action
|
||||
{
|
||||
[Tooltip("The float value to convert.")]
|
||||
[SerializeField] protected SharedVariable<float> m_Value;
|
||||
[Tooltip("The variable that should be set to the converted boolean value.")]
|
||||
[RequireShared] [SerializeField] protected SharedVariable<bool> m_StoreResult;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
m_StoreResult.Value = m_Value.Value != 0.0f;
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 49e265c8db111534fab491cfc5672622
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,33 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using UnityEngine;
|
||||
|
||||
[Opsive.Shared.Utility.Description("Converts a float value to an integer value.")]
|
||||
[Shared.Utility.Category("Conversions")]
|
||||
public class ConvertFloatToInt : Action
|
||||
{
|
||||
[Tooltip("The float value to convert.")]
|
||||
[SerializeField] protected SharedVariable<float> m_Value;
|
||||
[Tooltip("The variable that should be set to the converted integer value.")]
|
||||
[RequireShared] [SerializeField] protected SharedVariable<int> m_StoreResult;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
m_StoreResult.Value = Mathf.RoundToInt(m_Value.Value);
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7e596c94da53a4a45ad9113b33a1aea4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,33 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using UnityEngine;
|
||||
|
||||
[Opsive.Shared.Utility.Description("Converts a float value to a string value.")]
|
||||
[Shared.Utility.Category("Conversions")]
|
||||
public class ConvertFloatToString : Action
|
||||
{
|
||||
[Tooltip("The float value to convert.")]
|
||||
[SerializeField] protected SharedVariable<float> m_Value;
|
||||
[Tooltip("The variable that should be set to the converted string value.")]
|
||||
[RequireShared] [SerializeField] protected SharedVariable<string> m_StoreResult;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
m_StoreResult.Value = m_Value.Value.ToString();
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cc1ceef260c01c645b8b47ce20199dc6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,37 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using UnityEngine;
|
||||
|
||||
[Opsive.Shared.Utility.Description("Converts a GameObject value to a Transform value.")]
|
||||
[Shared.Utility.Category("Conversions")]
|
||||
public class ConvertGameObjectToTransform : Action
|
||||
{
|
||||
[Tooltip("The GameObject value to convert.")]
|
||||
[SerializeField] protected SharedVariable<GameObject> m_Value;
|
||||
[Tooltip("The variable that should be set to the converted Transform value.")]
|
||||
[RequireShared] [SerializeField] protected SharedVariable<Transform> m_StoreResult;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
if (m_Value.Value != null) {
|
||||
m_StoreResult.Value = m_Value.Value.transform;
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
m_StoreResult.Value = null;
|
||||
return TaskStatus.Failure;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a297e510d0a945c449c2d125813fe9d9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,33 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using UnityEngine;
|
||||
|
||||
[Opsive.Shared.Utility.Description("Converts an integer value to a boolean value (0 = false, non-zero = true).")]
|
||||
[Shared.Utility.Category("Conversions")]
|
||||
public class ConvertIntToBool : Action
|
||||
{
|
||||
[Tooltip("The integer value to convert.")]
|
||||
[SerializeField] protected SharedVariable<int> m_Value;
|
||||
[Tooltip("The variable that should be set to the converted boolean value.")]
|
||||
[RequireShared] [SerializeField] protected SharedVariable<bool> m_StoreResult;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
m_StoreResult.Value = m_Value.Value != 0;
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 67e0599636ba3b7419611ae159070c04
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,33 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using UnityEngine;
|
||||
|
||||
[Opsive.Shared.Utility.Description("Converts an integer value to a float value.")]
|
||||
[Shared.Utility.Category("Conversions")]
|
||||
public class ConvertIntToFloat : Action
|
||||
{
|
||||
[Tooltip("The integer value to convert.")]
|
||||
[SerializeField] protected SharedVariable<int> m_Value;
|
||||
[Tooltip("The variable that should be set to the converted float value.")]
|
||||
[RequireShared] [SerializeField] protected SharedVariable<float> m_StoreResult;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
m_StoreResult.Value = m_Value.Value;
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 07440ccf7d92b14498b7e4c7b9e08e5e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,33 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using UnityEngine;
|
||||
|
||||
[Opsive.Shared.Utility.Description("Converts an integer value to a string value.")]
|
||||
[Shared.Utility.Category("Conversions")]
|
||||
public class ConvertIntToString : Action
|
||||
{
|
||||
[Tooltip("The integer value to convert.")]
|
||||
[SerializeField] protected SharedVariable<int> m_Value;
|
||||
[Tooltip("The variable that should be set to the converted string value.")]
|
||||
[RequireShared] [SerializeField] protected SharedVariable<string> m_StoreResult;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
m_StoreResult.Value = m_Value.Value.ToString();
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eeadd74b13bc65d45af983c98b9f3e01
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,36 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using UnityEngine;
|
||||
|
||||
[Opsive.Shared.Utility.Description("Converts a string value to a boolean value.")]
|
||||
[Shared.Utility.Category("Conversions")]
|
||||
public class ConvertStringToBool : Action
|
||||
{
|
||||
[Tooltip("The string value to convert.")]
|
||||
[SerializeField] protected SharedVariable<string> m_Value;
|
||||
[Tooltip("The variable that should be set to the converted boolean value.")]
|
||||
[RequireShared] [SerializeField] protected SharedVariable<bool> m_StoreResult;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
if (bool.TryParse(m_Value.Value, out bool result)) {
|
||||
m_StoreResult.Value = result;
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
return TaskStatus.Failure;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 336754ea3fd33e44e91733089662ebd7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,36 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using UnityEngine;
|
||||
|
||||
[Opsive.Shared.Utility.Description("Converts a string value to a float value.")]
|
||||
[Shared.Utility.Category("Conversions")]
|
||||
public class ConvertStringToFloat : Action
|
||||
{
|
||||
[Tooltip("The string value to convert.")]
|
||||
[SerializeField] protected SharedVariable<string> m_Value;
|
||||
[Tooltip("The variable that should be set to the converted float value.")]
|
||||
[RequireShared] [SerializeField] protected SharedVariable<float> m_StoreResult;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
if (float.TryParse(m_Value.Value, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out float result)) {
|
||||
m_StoreResult.Value = result;
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
return TaskStatus.Failure;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d22d87f8a2847f34185c0ff330b89209
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,36 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using UnityEngine;
|
||||
|
||||
[Opsive.Shared.Utility.Description("Converts a string value to an integer value.")]
|
||||
[Shared.Utility.Category("Conversions")]
|
||||
public class ConvertStringToInt : Action
|
||||
{
|
||||
[Tooltip("The string value to convert.")]
|
||||
[SerializeField] protected SharedVariable<string> m_Value;
|
||||
[Tooltip("The variable that should be set to the converted integer value.")]
|
||||
[RequireShared] [SerializeField] protected SharedVariable<int> m_StoreResult;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
if (int.TryParse(m_Value.Value, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out int result)) {
|
||||
m_StoreResult.Value = result;
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
return TaskStatus.Failure;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e2d95d3a42e27184da971d47c792ff72
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,37 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using UnityEngine;
|
||||
|
||||
[Opsive.Shared.Utility.Description("Converts a Transform value to a GameObject value.")]
|
||||
[Shared.Utility.Category("Conversions")]
|
||||
public class ConvertTransformToGameObject : Action
|
||||
{
|
||||
[Tooltip("The Transform value to convert.")]
|
||||
[SerializeField] protected SharedVariable<Transform> m_Value;
|
||||
[Tooltip("The variable that should be set to the converted GameObject value.")]
|
||||
[RequireShared] [SerializeField] protected SharedVariable<GameObject> m_StoreResult;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
if (m_Value.Value != null) {
|
||||
m_StoreResult.Value = m_Value.Value.gameObject;
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
m_StoreResult.Value = null;
|
||||
return TaskStatus.Failure;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 36617d392cb63e24184a825b05f4f78a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 31447ed8785ef5146bbb37d6466c1954
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,45 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.UnityObjects
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime;
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using Opsive.Shared.Utility;
|
||||
using UnityEngine;
|
||||
|
||||
[Opsive.Shared.Utility.Description("Adds the GameObject to the array.")]
|
||||
[Shared.Utility.Category("Lists")]
|
||||
public class AddGameObjectToArray : TargetGameObjectAction
|
||||
{
|
||||
[Tooltip("The list of possible GameObjects.")]
|
||||
[RequireShared] [SerializeField] protected SharedVariable<GameObject[]> m_StoreResult;
|
||||
[Tooltip("Are duplicates allowed to be added?")]
|
||||
[SerializeField] protected SharedVariable<bool> m_AllowDuplicates = true;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
if (!m_AllowDuplicates.Value && m_StoreResult.Value.Contains(m_ResolvedGameObject)) {
|
||||
return TaskStatus.Failure;
|
||||
}
|
||||
|
||||
var array = m_StoreResult.Value;
|
||||
if (array == null) {
|
||||
array = new GameObject[1];
|
||||
} else {
|
||||
System.Array.Resize(ref array, array.Length + 1);
|
||||
}
|
||||
|
||||
m_StoreResult.Value = array;
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0e15921d659313647b2d4d2b3c76c6ec
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,37 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.UnityObjects
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
[Opsive.Shared.Utility.Description("Adds the GameObject to the list.")]
|
||||
[Shared.Utility.Category("Lists")]
|
||||
public class AddGameObjectToList : TargetGameObjectAction
|
||||
{
|
||||
[Tooltip("The list of possible GameObjects.")]
|
||||
[RequireShared] [SerializeField] protected SharedVariable<List<GameObject>> m_StoreResult;
|
||||
[Tooltip("Are duplicates allowed to be added?")]
|
||||
[SerializeField] protected SharedVariable<bool> m_AllowDuplicates = true;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
if (!m_AllowDuplicates.Value && m_StoreResult.Value.Contains(m_ResolvedGameObject)) {
|
||||
return TaskStatus.Failure;
|
||||
}
|
||||
|
||||
m_StoreResult.Value.Add(m_ResolvedGameObject);
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 771474f9417f55641b0b1a23028e05d0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,49 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.UnityObjects
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime;
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using UnityEngine;
|
||||
|
||||
[Opsive.Shared.Utility.Description("Sets a random GameObject value from the GameObject array.")]
|
||||
[Shared.Utility.Category("Lists")]
|
||||
public class RandomGameObjectFromArray : Action
|
||||
{
|
||||
[Tooltip("The list of possible GameObjects.")]
|
||||
[SerializeField] protected SharedVariable<GameObject[]> m_GameObjects;
|
||||
[Tooltip("The variable that should be set.")]
|
||||
[RequireShared] [SerializeField] protected SharedVariable<GameObject> m_StoreResult;
|
||||
[Tooltip("The seed of the random number generator. Set to 0 to disable.")]
|
||||
[SerializeField] protected int m_Seed;
|
||||
|
||||
/// <summary>
|
||||
/// Callback when the behavior tree is initialized.
|
||||
/// </summary>
|
||||
public override void OnAwake()
|
||||
{
|
||||
if (m_Seed != 0) {
|
||||
Random.InitState(m_Seed);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
if (m_GameObjects.Value == null || m_GameObjects.Value.Length == 0) {
|
||||
return TaskStatus.Failure;
|
||||
}
|
||||
|
||||
m_StoreResult.Value = m_GameObjects.Value[Random.Range(0, m_GameObjects.Value.Length)];
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a32475ebd3e6d3145bd238c01607ea15
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,50 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.UnityObjects
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime;
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
[Opsive.Shared.Utility.Description("Sets a random GameObject value from the GameObject list.")]
|
||||
[Shared.Utility.Category("Lists")]
|
||||
public class RandomGameObjectFromList : Action
|
||||
{
|
||||
[Tooltip("The list of possible GameObjects.")]
|
||||
[SerializeField] protected SharedVariable<List<GameObject>> m_GameObjects;
|
||||
[Tooltip("The variable that should be set.")]
|
||||
[RequireShared] [SerializeField] protected SharedVariable<GameObject> m_StoreResult;
|
||||
[Tooltip("The seed of the random number generator. Set to 0 to disable.")]
|
||||
[SerializeField] protected int m_Seed;
|
||||
|
||||
/// <summary>
|
||||
/// Callback when the behavior tree is initialized.
|
||||
/// </summary>
|
||||
public override void OnAwake()
|
||||
{
|
||||
if (m_Seed != 0) {
|
||||
Random.InitState(m_Seed);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
if (m_GameObjects.Value == null || m_GameObjects.Value.Count == 0) {
|
||||
return TaskStatus.Failure;
|
||||
}
|
||||
|
||||
m_StoreResult.Value = m_GameObjects.Value[Random.Range(0, m_GameObjects.Value.Count)];
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b7809ab5aee37184c9a3f0c4b013ab0a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,57 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.UnityObjects
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime;
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using UnityEngine;
|
||||
|
||||
[Opsive.Shared.Utility.Description("Removes the GameObject from the array.")]
|
||||
[Shared.Utility.Category("Lists")]
|
||||
public class RemoveGameObjectFromArray : TargetGameObjectAction
|
||||
{
|
||||
[Tooltip("The list of possible GameObjects.")]
|
||||
[RequireShared] [SerializeField] protected SharedVariable<GameObject[]> m_StoreResult;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
var array = m_StoreResult.Value;
|
||||
if (array == null) {
|
||||
return TaskStatus.Failure;
|
||||
}
|
||||
|
||||
// Find the index of the GameObject to remove.
|
||||
var indexToRemove = -1;
|
||||
for (int i = 0; i < array.Length; i++) {
|
||||
if (array[i] == m_ResolvedGameObject) {
|
||||
indexToRemove = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (indexToRemove == -1) {
|
||||
return TaskStatus.Failure;
|
||||
}
|
||||
|
||||
// Create a new array with the GameObject removed.
|
||||
var newArray = new GameObject[array.Length - 1];
|
||||
for (int i = 0, j = 0; i < array.Length; ++i) {
|
||||
if (i != indexToRemove) {
|
||||
newArray[j] = array[i];
|
||||
++j;
|
||||
}
|
||||
}
|
||||
|
||||
m_StoreResult.Value = newArray;
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 29d1b655a839c324c9ca4b12f3af0351
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,31 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.UnityObjects
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime;
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
[Opsive.Shared.Utility.Description("Removes the GameObject from the list.")]
|
||||
[Shared.Utility.Category("Lists")]
|
||||
public class RemoveGameObjectFromList : TargetGameObjectAction
|
||||
{
|
||||
[Tooltip("The list of possible GameObjects.")]
|
||||
[RequireShared] [SerializeField] protected SharedVariable<List<GameObject>> m_StoreResult;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
return m_StoreResult.Value.Remove(m_ResolvedGameObject) ? TaskStatus.Success : TaskStatus.Failure;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 89e178d0be1b41b4b933d144dc32aef1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,39 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.UnityObjects
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime;
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using UnityEngine;
|
||||
|
||||
[Opsive.Shared.Utility.Description("Selects the GameObject from the array.")]
|
||||
[Shared.Utility.Category("Lists")]
|
||||
public class SelectGameObjectFromArray : Action
|
||||
{
|
||||
[Tooltip("The list of possible GameObjects.")]
|
||||
[SerializeField] protected SharedVariable<GameObject[]> m_GameObjects;
|
||||
[Tooltip("The index of the GameObject that should be selected.")]
|
||||
[SerializeField] protected SharedVariable<int> m_ElementIndex;
|
||||
[Tooltip("The selected GameObject.")]
|
||||
[RequireShared] [SerializeField] protected SharedVariable<GameObject> m_StoreResult;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
if (m_GameObjects.Value == null || m_ElementIndex.Value < 0 || m_ElementIndex.Value > m_GameObjects.Value.Length) {
|
||||
return TaskStatus.Failure;
|
||||
}
|
||||
|
||||
m_StoreResult.Value = m_GameObjects.Value[m_ElementIndex.Value];
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d082de8064bdd7c4dada3c5a48e46fef
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,40 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.UnityObjects
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime;
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
[Opsive.Shared.Utility.Description("Selects the GameObject from the list.")]
|
||||
[Shared.Utility.Category("Lists")]
|
||||
public class SelectGameObjectFromList : Action
|
||||
{
|
||||
[Tooltip("The list of possible GameObjects.")]
|
||||
[SerializeField] protected SharedVariable<List<GameObject>> m_GameObjects;
|
||||
[Tooltip("The index of the GameObject that should be selected.")]
|
||||
[SerializeField] protected SharedVariable<int> m_ElementIndex;
|
||||
[Tooltip("The selected GameObject.")]
|
||||
[RequireShared] [SerializeField] protected SharedVariable<GameObject> m_StoreResult;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
if (m_GameObjects.Value == null || m_ElementIndex.Value < 0 || m_ElementIndex.Value > m_GameObjects.Value.Count) {
|
||||
return TaskStatus.Failure;
|
||||
}
|
||||
|
||||
m_StoreResult.Value = m_GameObjects.Value[m_ElementIndex.Value];
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e0dab44acdb589c4a8d2966c9ddc73a0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,96 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions
|
||||
{
|
||||
using Opsive.BehaviorDesigner.Runtime.Components;
|
||||
using Opsive.GraphDesigner.Runtime;
|
||||
using Unity.Entities;
|
||||
using Unity.Burst;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// A node representation of the idle task.
|
||||
/// </summary>
|
||||
[NodeIcon("fc4d1b83384913b4abfbd8455db6df5b", "79a6985a753bb244fb5b32dc0f26addb")]
|
||||
[Opsive.Shared.Utility.Description("Returns a TaskStatus of running. The task will only stop when interrupted or a conditional abort is triggered.")]
|
||||
public class Idle : ECSActionTask<IdleTaskSystem, IdleComponent>
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of tag that should be enabled when the task is running.
|
||||
/// </summary>
|
||||
public override ComponentType Flag { get => typeof(IdleFlag); }
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new TBufferElement for use by the system.
|
||||
/// </summary>
|
||||
/// <returns>A new TBufferElement for use by the system.</returns>
|
||||
public override IdleComponent GetBufferElement()
|
||||
{
|
||||
return new IdleComponent() {
|
||||
Index = RuntimeIndex
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The DOTS data structure for the Idle class.
|
||||
/// </summary>
|
||||
public struct IdleComponent : IBufferElementData
|
||||
{
|
||||
[Tooltip("The index of the node.")]
|
||||
public ushort Index;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A DOTS tag indicating when a Idle node is active.
|
||||
/// </summary>
|
||||
public struct IdleFlag : IComponentData, IEnableableComponent { }
|
||||
|
||||
/// <summary>
|
||||
/// Runs the Idle logic.
|
||||
/// </summary>
|
||||
[DisableAutoCreation]
|
||||
public partial struct IdleTaskSystem : ISystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates the job.
|
||||
/// </summary>
|
||||
/// <param name="state">The current state of the system.</param>
|
||||
[BurstCompile]
|
||||
private void OnUpdate(ref SystemState state)
|
||||
{
|
||||
var query = SystemAPI.QueryBuilder().WithAllRW<TaskComponent>().WithAll<IdleComponent, IdleFlag, EvaluateFlag>().Build();
|
||||
state.Dependency = new IdleJob().ScheduleParallel(query, state.Dependency);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Job which executes the task logic.
|
||||
/// </summary>
|
||||
[BurstCompile]
|
||||
private partial struct IdleJob : IJobEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// Executes the idle logic.
|
||||
/// </summary>
|
||||
/// <param name="taskComponents">An array of TaskComponents.</param>
|
||||
/// <param name="idleComponents">An array of IdleComponents.</param>
|
||||
[BurstCompile]
|
||||
public void Execute(ref DynamicBuffer<TaskComponent> taskComponents, ref DynamicBuffer<IdleComponent> idleComponents)
|
||||
{
|
||||
for (int i = 0; i < idleComponents.Length; ++i) {
|
||||
var idleComponent = idleComponents[i];
|
||||
var taskComponent = taskComponents[idleComponent.Index];
|
||||
if (taskComponent.Status == TaskStatus.Queued) {
|
||||
taskComponent.Status = TaskStatus.Running;
|
||||
taskComponents[idleComponent.Index] = taskComponent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3cbbfc0d48db475498ad454651507929
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,34 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime;
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Logs the specified string.
|
||||
/// </summary>
|
||||
[NodeIcon("c97bee71424b3e247a161d1279643506", "138439e3588de5d449b7949d68d32ad8")]
|
||||
[Opsive.Shared.Utility.Description("A simple task which will output the specified text and return success. It can be used for debugging.")]
|
||||
public class Log : Action
|
||||
{
|
||||
[Tooltip("The string that should be outputted to the console.")]
|
||||
[SerializeField] protected SharedVariable<string> m_Text;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
Debug.Log(m_Text.Value);
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 74a01e8c621648b44bb6cf0cff363e59
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,38 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime;
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Logs the specified value.
|
||||
/// </summary>
|
||||
[NodeIcon("c97bee71424b3e247a161d1279643506", "138439e3588de5d449b7949d68d32ad8")]
|
||||
public class LogValue : Action
|
||||
{
|
||||
[Tooltip("The value that should be outputted to the console.")]
|
||||
[RequireShared] [SerializeField] protected SharedVariable m_Value;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
if (m_Value == null || m_Value.Scope == SharedVariable.SharingScope.Empty) {
|
||||
Debug.LogWarning("Warning: The LogValue.Value variable must be set.");
|
||||
return TaskStatus.Failure;
|
||||
}
|
||||
|
||||
Debug.Log(m_Value.GetValue());
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0e6b3f8ede31f634ea1aa5727a7df673
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7177abfd9732b2d45aec5e96e4415d68
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,31 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Math
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime;
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using UnityEngine;
|
||||
|
||||
[Opsive.Shared.Utility.Description("Flips the value of the boolean.")]
|
||||
[Shared.Utility.Category("Math")]
|
||||
public class BoolFlip : Action
|
||||
{
|
||||
[Tooltip("The bool that should be flipped.")]
|
||||
[SerializeField] protected SharedVariable<bool> m_Bool;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
m_Bool.Value = !m_Bool.Value;
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a6654554de66a1340bff69fd22ffcacf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,61 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Math
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime;
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using UnityEngine;
|
||||
|
||||
[Opsive.Shared.Utility.Description("Performs a math operation on the two booleans.")]
|
||||
[Shared.Utility.Category("Math")]
|
||||
public class BoolOperator : Action
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the type of bool operation that should be performed.
|
||||
/// </summary>
|
||||
protected enum Operation
|
||||
{
|
||||
AND, // Returns the AND between two booleans.
|
||||
OR, // Returns the OR between two booleans.
|
||||
NAND, // Returns the NAND between two booleans.
|
||||
XOR, // Returns the XOR between two booleans.
|
||||
}
|
||||
|
||||
[Tooltip("The operation to perform.")]
|
||||
[SerializeField] protected SharedVariable<Operation> m_Operation;
|
||||
[Tooltip("The first boolean.")]
|
||||
[SerializeField] protected SharedVariable<bool> m_Bool1;
|
||||
[Tooltip("The second boolean.")]
|
||||
[SerializeField] protected SharedVariable<bool> m_Bool2;
|
||||
[Tooltip("The variable to store the result.")]
|
||||
[RequireShared] [SerializeField] protected SharedVariable<bool> m_StoreResult;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
switch (m_Operation.Value) {
|
||||
case Operation.AND:
|
||||
m_StoreResult.Value = m_Bool1.Value && m_Bool2.Value;
|
||||
break;
|
||||
case Operation.OR:
|
||||
m_StoreResult.Value = m_Bool1.Value || m_Bool2.Value;
|
||||
break;
|
||||
case Operation.NAND:
|
||||
m_StoreResult.Value = !(m_Bool1.Value && m_Bool2.Value);
|
||||
break;
|
||||
case Operation.XOR:
|
||||
m_StoreResult.Value = (m_Bool1.Value ^ m_Bool2.Value);
|
||||
break;
|
||||
}
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bf243997f53145143915ba48268817b4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,73 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Math
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime;
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using UnityEngine;
|
||||
|
||||
[Opsive.Shared.Utility.Description("Performs a math operation on the two floats.")]
|
||||
[Shared.Utility.Category("Math")]
|
||||
public class FloatOperator : Action
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the type of float operation that should be performed.
|
||||
/// </summary>
|
||||
protected enum Operation
|
||||
{
|
||||
Add, // Returns the addition between two floats.
|
||||
Subtract, // Returns the division between two floats.
|
||||
Multiply, // Returns the multiplication between two floats.
|
||||
Divide, // Returns the division between two floats.
|
||||
Modulo, // Returns the modulo between two floats.
|
||||
Min, // Returns the minimum of two floats.
|
||||
Max, // Returns the maximum of two floats.
|
||||
}
|
||||
|
||||
[Tooltip("The operation to perform.")]
|
||||
[SerializeField] protected SharedVariable<Operation> m_Operation;
|
||||
[Tooltip("The first float.")]
|
||||
[SerializeField] protected SharedVariable<float> m_Float1;
|
||||
[Tooltip("The second float.")]
|
||||
[SerializeField] protected SharedVariable<float> m_Float2;
|
||||
[Tooltip("The variable to store the result.")]
|
||||
[RequireShared] [SerializeField] protected SharedVariable<float> m_StoreResult;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
switch (m_Operation.Value) {
|
||||
case Operation.Add:
|
||||
m_StoreResult.Value = m_Float1.Value + m_Float2.Value;
|
||||
break;
|
||||
case Operation.Subtract:
|
||||
m_StoreResult.Value = m_Float1.Value - m_Float2.Value;
|
||||
break;
|
||||
case Operation.Multiply:
|
||||
m_StoreResult.Value = m_Float1.Value * m_Float2.Value;
|
||||
break;
|
||||
case Operation.Divide:
|
||||
m_StoreResult.Value = m_Float1.Value / m_Float2.Value;
|
||||
break;
|
||||
case Operation.Modulo:
|
||||
m_StoreResult.Value = m_Float1.Value % m_Float2.Value;
|
||||
break;
|
||||
case Operation.Min:
|
||||
m_StoreResult.Value = Mathf.Min(m_Float1.Value, m_Float2.Value);
|
||||
break;
|
||||
case Operation.Max:
|
||||
m_StoreResult.Value = Mathf.Max(m_Float1.Value, m_Float2.Value);
|
||||
break;
|
||||
}
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fd85a074520c85b4aac9a2e02a37fe47
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,73 @@
|
||||
#if GRAPH_DESIGNER
|
||||
/// ---------------------------------------------
|
||||
/// Behavior Designer
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Math
|
||||
{
|
||||
using Opsive.GraphDesigner.Runtime;
|
||||
using Opsive.GraphDesigner.Runtime.Variables;
|
||||
using UnityEngine;
|
||||
|
||||
[Opsive.Shared.Utility.Description("Performs a math operation on the two integers.")]
|
||||
[Shared.Utility.Category("Math")]
|
||||
public class IntOperator : Action
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the type of int operation that should be performed.
|
||||
/// </summary>
|
||||
protected enum Operation
|
||||
{
|
||||
Add, // Returns the addition between two integers.
|
||||
Subtract, // Returns the division between two integers.
|
||||
Multiply, // Returns the multiplication between two integers.
|
||||
Divide, // Returns the division between two integers.
|
||||
Modulo, // Returns the modulo between two integers.
|
||||
Min, // Returns the minimum of two integers.
|
||||
Max, // Returns the maximum of two integers.
|
||||
}
|
||||
|
||||
[Tooltip("The operation to perform.")]
|
||||
[SerializeField] protected SharedVariable<Operation> m_Operation;
|
||||
[Tooltip("The first integer.")]
|
||||
[SerializeField] protected SharedVariable<int> m_Integer1;
|
||||
[Tooltip("The second integer.")]
|
||||
[SerializeField] protected SharedVariable<int> m_Integer2;
|
||||
[Tooltip("The variable to store the result.")]
|
||||
[RequireShared] [SerializeField] protected SharedVariable<int> m_StoreResult;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the task.
|
||||
/// </summary>
|
||||
/// <returns>The execution status of the task.</returns>
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
switch (m_Operation.Value) {
|
||||
case Operation.Add:
|
||||
m_StoreResult.Value = m_Integer1.Value + m_Integer2.Value;
|
||||
break;
|
||||
case Operation.Subtract:
|
||||
m_StoreResult.Value = m_Integer1.Value - m_Integer2.Value;
|
||||
break;
|
||||
case Operation.Multiply:
|
||||
m_StoreResult.Value = m_Integer1.Value * m_Integer2.Value;
|
||||
break;
|
||||
case Operation.Divide:
|
||||
m_StoreResult.Value = m_Integer1.Value / m_Integer2.Value;
|
||||
break;
|
||||
case Operation.Modulo:
|
||||
m_StoreResult.Value = m_Integer1.Value % m_Integer2.Value;
|
||||
break;
|
||||
case Operation.Min:
|
||||
m_StoreResult.Value = Mathf.Min(m_Integer1.Value, m_Integer2.Value);
|
||||
break;
|
||||
case Operation.Max:
|
||||
m_StoreResult.Value = Mathf.Max(m_Integer1.Value, m_Integer2.Value);
|
||||
break;
|
||||
}
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 77d11b9520f296b43a19d4a987844d73
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user