922 lines
36 KiB
C#
Executable File
922 lines
36 KiB
C#
Executable File
using UnityEngine;
|
|
#if ENABLE_MULTIPLAYER
|
|
using UnityEngine.Networking;
|
|
#endif
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using BehaviorDesigner.Runtime.Tasks;
|
|
|
|
namespace BehaviorDesigner.Runtime
|
|
{
|
|
[System.Serializable]
|
|
public abstract class Behavior : MonoBehaviour, IBehavior
|
|
{
|
|
[SerializeField] [UnityEngine.Tooltip("If true, the behavior tree will start running when the component is enabled.")]
|
|
private bool startWhenEnabled = true;
|
|
public bool StartWhenEnabled { get { return startWhenEnabled; } set { startWhenEnabled = value; } }
|
|
[SerializeField] [UnityEngine.Tooltip("Specifies if the behavior tree should load in a separate thread." +
|
|
"Because Unity does not allow for API calls to be made on worker threads this option should be disabled if you are using property mappings" +
|
|
"for the shared variables.")]
|
|
private bool asynchronousLoad = false;
|
|
public bool AsynchronousLoad { get { return asynchronousLoad; } set { asynchronousLoad = value; } }
|
|
|
|
[SerializeField] [UnityEngine.Tooltip("If true, the behavior tree will pause when the component is disabled. If false, the behavior tree will end.")]
|
|
private bool pauseWhenDisabled = false;
|
|
public bool PauseWhenDisabled { get { return pauseWhenDisabled; } set { pauseWhenDisabled = value; } }
|
|
|
|
[SerializeField] [UnityEngine.Tooltip("If true, the behavior tree will restart from the beginning when it has completed execution. If false, the behavior tree will end.")]
|
|
private bool restartWhenComplete = false;
|
|
public bool RestartWhenComplete { get { return restartWhenComplete; } set { restartWhenComplete = value; } }
|
|
|
|
[SerializeField] [UnityEngine.Tooltip("Used for debugging. If enabled, the behavior tree will output any time a task status changes, such as it starting or stopping.")]
|
|
private bool logTaskChanges = false;
|
|
public bool LogTaskChanges { get { return logTaskChanges; } set { logTaskChanges = value; } }
|
|
|
|
[SerializeField] [UnityEngine.Tooltip("A numerical grouping of behavior trees. Can be used to easily find behavior trees.")]
|
|
private int group = 0;
|
|
public int Group { get { return group; } set { group = value; } }
|
|
|
|
[SerializeField] [UnityEngine.Tooltip("If true, the variables and task public variables will be reset to their original values when the tree restarts.")]
|
|
private bool resetValuesOnRestart = false;
|
|
public bool ResetValuesOnRestart { get { return resetValuesOnRestart; } set { resetValuesOnRestart = value; } }
|
|
|
|
// reference to an external behavior tree, useful if creating a behavior tree from script
|
|
[SerializeField] [UnityEngine.Tooltip("A field to specify the external behavior tree that should be run when this behavior tree starts.")]
|
|
private ExternalBehavior externalBehavior;
|
|
public ExternalBehavior ExternalBehavior
|
|
{
|
|
get { return externalBehavior; }
|
|
set
|
|
{
|
|
if (externalBehavior == value) {
|
|
return;
|
|
}
|
|
if (BehaviorManager.instance != null) {
|
|
BehaviorManager.instance.DisableBehavior(this);
|
|
}
|
|
// If the external tree has been initialized then it has been manually deserialized. Don't deserialize again.
|
|
if (value != null && value.Initialized) {
|
|
// Store a reference to the current tree's variables so they can inherit the external tree variables.
|
|
var variables = mBehaviorSource.GetAllVariables();
|
|
mBehaviorSource = value.BehaviorSource;
|
|
mBehaviorSource.HasSerialized = true;
|
|
if (variables != null) {
|
|
for (int i = 0; i < variables.Count; ++i) {
|
|
if (variables[i] == null) {
|
|
continue;
|
|
}
|
|
mBehaviorSource.SetVariable(variables[i].Name, variables[i]);
|
|
}
|
|
}
|
|
} else {
|
|
mBehaviorSource.HasSerialized = false;
|
|
hasInheritedVariables = false;
|
|
}
|
|
initialized = false;
|
|
externalBehavior = value;
|
|
if (startWhenEnabled) {
|
|
EnableBehavior();
|
|
}
|
|
}
|
|
}
|
|
private bool hasInheritedVariables = false;
|
|
public bool HasInheritedVariables { get { return hasInheritedVariables; } set { hasInheritedVariables = value; } }
|
|
public string BehaviorName { get { return mBehaviorSource.behaviorName; } set { mBehaviorSource.behaviorName = value; } }
|
|
public string BehaviorDescription { get { return mBehaviorSource.behaviorDescription; } set { mBehaviorSource.behaviorDescription = value; } }
|
|
|
|
[SerializeField]
|
|
private BehaviorSource mBehaviorSource;
|
|
public BehaviorSource GetBehaviorSource() { return mBehaviorSource; }
|
|
public void SetBehaviorSource(BehaviorSource behaviorSource) { mBehaviorSource = behaviorSource; }
|
|
public UnityEngine.Object GetObject() { return this; }
|
|
public string GetOwnerName() { return gameObject.name; }
|
|
|
|
private bool isPaused = false;
|
|
private TaskStatus executionStatus = TaskStatus.Inactive;
|
|
public TaskStatus ExecutionStatus { get { return executionStatus; } set { executionStatus = value; } }
|
|
private bool initialized = false;
|
|
|
|
private Dictionary<Task, Dictionary<string, object>> defaultValues;
|
|
private Dictionary<SharedVariable, object> defaultVariableValues;
|
|
|
|
// events
|
|
public enum EventTypes { OnCollisionEnter, OnCollisionExit, OnTriggerEnter, OnTriggerExit,
|
|
OnCollisionEnter2D, OnCollisionExit2D, OnTriggerEnter2D, OnTriggerExit2D,
|
|
OnControllerColliderHit, OnLateUpdate, OnFixedUpdate, OnAnimatorIK, None }
|
|
private bool[] hasEvent = new bool[(int)EventTypes.None];
|
|
public bool[] HasEvent { get { return hasEvent; } }
|
|
|
|
// coroutines
|
|
private Dictionary<string, List<TaskCoroutine>> activeTaskCoroutines = null;
|
|
|
|
// events
|
|
public delegate void BehaviorHandler(Behavior behavior);
|
|
public event BehaviorHandler OnBehaviorStart;
|
|
public event BehaviorHandler OnBehaviorRestart;
|
|
public event BehaviorHandler OnBehaviorEnd;
|
|
private Dictionary<Type, Dictionary<string, Delegate>> eventTable;
|
|
|
|
#if UNITY_EDITOR || DLL_DEBUG || DLL_RELEASE
|
|
// gizmo drawings
|
|
public enum GizmoViewMode { Running, Always, Selected, Never }
|
|
public GizmoViewMode gizmoViewMode;
|
|
public bool showBehaviorDesignerGizmo = true;
|
|
#endif
|
|
|
|
public Behavior()
|
|
{
|
|
mBehaviorSource = new BehaviorSource(this);
|
|
}
|
|
|
|
public void Start()
|
|
{
|
|
if (startWhenEnabled) {
|
|
EnableBehavior();
|
|
}
|
|
}
|
|
|
|
public void EnableBehavior()
|
|
{
|
|
// create the behavior manager if it doesn't already exist
|
|
CreateBehaviorManager();
|
|
if (BehaviorManager.instance != null) {
|
|
BehaviorManager.instance.EnableBehavior(this);
|
|
}
|
|
}
|
|
|
|
public void DisableBehavior()
|
|
{
|
|
if (BehaviorManager.instance != null) {
|
|
BehaviorManager.instance.DisableBehavior(this, pauseWhenDisabled);
|
|
isPaused = pauseWhenDisabled;
|
|
}
|
|
}
|
|
|
|
public void DisableBehavior(bool pause)
|
|
{
|
|
if (BehaviorManager.instance != null) {
|
|
BehaviorManager.instance.DisableBehavior(this, pause);
|
|
isPaused = pause;
|
|
}
|
|
}
|
|
|
|
public void OnEnable()
|
|
{
|
|
if (BehaviorManager.instance != null && isPaused) {
|
|
BehaviorManager.instance.EnableBehavior(this);
|
|
isPaused = false;
|
|
} else if (startWhenEnabled && initialized) {
|
|
EnableBehavior();
|
|
}
|
|
}
|
|
|
|
public void OnDisable()
|
|
{
|
|
DisableBehavior();
|
|
}
|
|
|
|
public void OnDestroy()
|
|
{
|
|
if (BehaviorManager.instance != null) {
|
|
BehaviorManager.instance.DestroyBehavior(this);
|
|
}
|
|
}
|
|
|
|
// Support blackboard variables:
|
|
public SharedVariable GetVariable(string name)
|
|
{
|
|
CheckForSerialization();
|
|
return mBehaviorSource.GetVariable(name);
|
|
}
|
|
|
|
public void SetVariable(string name, SharedVariable item)
|
|
{
|
|
CheckForSerialization();
|
|
mBehaviorSource.SetVariable(name, item);
|
|
}
|
|
|
|
public void SetVariableValue(string name, object value)
|
|
{
|
|
var sharedVariable = GetVariable(name);
|
|
if (sharedVariable != null) {
|
|
if (value is SharedVariable) {
|
|
var sharedVariableValue = value as SharedVariable;
|
|
if (!string.IsNullOrEmpty(sharedVariableValue.PropertyMapping)) {
|
|
sharedVariable.PropertyMapping = sharedVariableValue.PropertyMapping;
|
|
sharedVariable.PropertyMappingOwner = sharedVariableValue.PropertyMappingOwner;
|
|
sharedVariable.InitializePropertyMapping(mBehaviorSource);
|
|
} else {
|
|
sharedVariable.SetValue(sharedVariableValue.GetValue());
|
|
}
|
|
} else {
|
|
sharedVariable.SetValue(value);
|
|
}
|
|
} else {
|
|
if (value is SharedVariable) {
|
|
// Add the new variable
|
|
var sharedVariableValue = value as SharedVariable;
|
|
var variable = TaskUtility.CreateInstance(sharedVariableValue.GetType()) as SharedVariable;
|
|
variable.Name = sharedVariableValue.Name;
|
|
variable.IsShared = sharedVariableValue.IsShared;
|
|
variable.IsGlobal = sharedVariableValue.IsGlobal;
|
|
if (!string.IsNullOrEmpty(sharedVariableValue.PropertyMapping)) {
|
|
variable.PropertyMapping = sharedVariableValue.PropertyMapping;
|
|
variable.PropertyMappingOwner = sharedVariableValue.PropertyMappingOwner;
|
|
variable.InitializePropertyMapping(mBehaviorSource);
|
|
} else {
|
|
variable.SetValue(sharedVariableValue.GetValue());
|
|
}
|
|
mBehaviorSource.SetVariable(name, variable);
|
|
} else {
|
|
Debug.LogError("Error: No variable exists with name " + name);
|
|
}
|
|
}
|
|
}
|
|
|
|
public List<SharedVariable> GetAllVariables()
|
|
{
|
|
CheckForSerialization();
|
|
return mBehaviorSource.GetAllVariables();
|
|
}
|
|
|
|
public void CheckForSerialization()
|
|
{
|
|
CheckForSerialization(false, Application.isPlaying);
|
|
}
|
|
|
|
public void CheckForSerialization(bool forceSerialization, bool isPlaying)
|
|
{
|
|
if (externalBehavior != null) {
|
|
var hasSerialized = mBehaviorSource.HasSerialized;
|
|
mBehaviorSource.CheckForSerialization(forceSerialization || !hasSerialized, null, isPlaying);
|
|
var variables = mBehaviorSource.GetAllVariables();
|
|
hasInheritedVariables = variables != null && variables.Count > 0;
|
|
externalBehavior.BehaviorSource.Owner = ExternalBehavior;
|
|
externalBehavior.BehaviorSource.CheckForSerialization(forceSerialization || !hasSerialized, GetBehaviorSource(), isPlaying);
|
|
externalBehavior.BehaviorSource.EntryTask = mBehaviorSource.EntryTask;
|
|
if (hasInheritedVariables) {
|
|
for (int i = 0; i < variables.Count; ++i) {
|
|
if (variables[i] == null) {
|
|
continue;
|
|
}
|
|
mBehaviorSource.SetVariable(variables[i].Name, variables[i]);
|
|
}
|
|
}
|
|
} else {
|
|
mBehaviorSource.CheckForSerialization(false, null, isPlaying);
|
|
}
|
|
}
|
|
|
|
// Support collisions/triggers:
|
|
public void OnCollisionEnter(Collision collision)
|
|
{
|
|
if (hasEvent[(int)EventTypes.OnCollisionEnter] && BehaviorManager.instance != null) {
|
|
BehaviorManager.instance.BehaviorOnCollisionEnter(collision, this);
|
|
}
|
|
}
|
|
|
|
public void OnCollisionExit(Collision collision)
|
|
{
|
|
if (hasEvent[(int)EventTypes.OnCollisionExit] && BehaviorManager.instance != null) {
|
|
BehaviorManager.instance.BehaviorOnCollisionExit(collision, this);
|
|
}
|
|
}
|
|
|
|
public void OnTriggerEnter(Collider other)
|
|
{
|
|
if (hasEvent[(int)EventTypes.OnTriggerEnter] && BehaviorManager.instance != null) {
|
|
BehaviorManager.instance.BehaviorOnTriggerEnter(other, this);
|
|
}
|
|
}
|
|
|
|
public void OnTriggerExit(Collider other)
|
|
{
|
|
if (hasEvent[(int)EventTypes.OnTriggerExit] && BehaviorManager.instance != null) {
|
|
BehaviorManager.instance.BehaviorOnTriggerExit(other, this);
|
|
}
|
|
}
|
|
|
|
public void OnCollisionEnter2D(Collision2D collision)
|
|
{
|
|
if (hasEvent[(int)EventTypes.OnCollisionEnter2D] && BehaviorManager.instance != null) {
|
|
BehaviorManager.instance.BehaviorOnCollisionEnter2D(collision, this);
|
|
}
|
|
}
|
|
|
|
public void OnCollisionExit2D(Collision2D collision)
|
|
{
|
|
if (hasEvent[(int)EventTypes.OnCollisionExit2D] && BehaviorManager.instance != null) {
|
|
BehaviorManager.instance.BehaviorOnCollisionExit2D(collision, this);
|
|
}
|
|
}
|
|
|
|
public void OnTriggerEnter2D(Collider2D other)
|
|
{
|
|
if (hasEvent[(int)EventTypes.OnTriggerEnter2D] && BehaviorManager.instance != null) {
|
|
BehaviorManager.instance.BehaviorOnTriggerEnter2D(other, this);
|
|
}
|
|
}
|
|
|
|
public void OnTriggerExit2D(Collider2D other)
|
|
{
|
|
if (hasEvent[(int)EventTypes.OnTriggerExit2D] && BehaviorManager.instance != null) {
|
|
BehaviorManager.instance.BehaviorOnTriggerExit2D(other, this);
|
|
}
|
|
}
|
|
|
|
public void OnControllerColliderHit(ControllerColliderHit hit)
|
|
{
|
|
if (hasEvent[(int)EventTypes.OnControllerColliderHit] && BehaviorManager.instance != null) {
|
|
BehaviorManager.instance.BehaviorOnControllerColliderHit(hit, this);
|
|
}
|
|
}
|
|
|
|
public void OnAnimatorIK()
|
|
{
|
|
if (hasEvent[(int)EventTypes.OnAnimatorIK] && BehaviorManager.instance != null) {
|
|
BehaviorManager.instance.BehaviorOnAnimatorIK(this);
|
|
}
|
|
}
|
|
|
|
#if UNITY_EDITOR || DLL_DEBUG || DLL_RELEASE
|
|
public void OnDrawGizmos()
|
|
{
|
|
DrawTaskGizmos(false);
|
|
}
|
|
|
|
public void OnDrawGizmosSelected()
|
|
{
|
|
if (showBehaviorDesignerGizmo) {
|
|
Gizmos.DrawIcon(transform.position, "Behavior Designer Scene Icon.png");
|
|
}
|
|
DrawTaskGizmos(true);
|
|
}
|
|
|
|
private void DrawTaskGizmos(bool selected)
|
|
{
|
|
if (gizmoViewMode == GizmoViewMode.Never || (gizmoViewMode == GizmoViewMode.Selected && !selected)) {
|
|
return;
|
|
}
|
|
|
|
if (gizmoViewMode == GizmoViewMode.Running || gizmoViewMode == GizmoViewMode.Always || (Application.isPlaying && ExecutionStatus == TaskStatus.Running) || !Application.isPlaying) {
|
|
CheckForSerialization();
|
|
|
|
DrawTaskGizmos(mBehaviorSource.RootTask);
|
|
|
|
var detachedTasks = mBehaviorSource.DetachedTasks;
|
|
if (detachedTasks != null) {
|
|
for (int i = 0; i < detachedTasks.Count; ++i) {
|
|
DrawTaskGizmos(detachedTasks[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DrawTaskGizmos(Task task)
|
|
{
|
|
if (task == null) {
|
|
return;
|
|
}
|
|
|
|
// If the view mode is Running then only draw the gizmo when the task is reevaluating (with conditional aborts) or is currently running.
|
|
if (gizmoViewMode == GizmoViewMode.Running && (!task.NodeData.IsReevaluating && (task.NodeData.IsReevaluating || task.NodeData.ExecutionStatus != TaskStatus.Running))) {
|
|
return;
|
|
}
|
|
|
|
task.OnDrawGizmos();
|
|
|
|
if (task is ParentTask) {
|
|
var parentTask = task as ParentTask;
|
|
if (parentTask.Children != null) {
|
|
for (int i = 0; i < parentTask.Children.Count; ++i) {
|
|
DrawTaskGizmos(parentTask.Children[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
public T FindTask<T>() where T : Task
|
|
{
|
|
CheckForSerialization();
|
|
|
|
return FindTask<T>(mBehaviorSource.RootTask);
|
|
}
|
|
|
|
private T FindTask<T>(Task task) where T : Task
|
|
{
|
|
if (task.GetType().Equals(typeof(T))) {
|
|
return (T)task;
|
|
}
|
|
|
|
ParentTask parentTask;
|
|
if ((parentTask = task as ParentTask) != null) {
|
|
if (parentTask.Children != null) {
|
|
for (int i = 0; i < parentTask.Children.Count; ++i) {
|
|
T foundTask = null;
|
|
if ((foundTask = FindTask<T>(parentTask.Children[i])) != null) {
|
|
return foundTask;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public List<T> FindTasks<T>() where T : Task
|
|
{
|
|
CheckForSerialization();
|
|
|
|
List<T> tasks = new List<T>();
|
|
FindTasks<T>(mBehaviorSource.RootTask, ref tasks);
|
|
return tasks;
|
|
}
|
|
|
|
private void FindTasks<T>(Task task, ref List<T> taskList) where T : Task
|
|
{
|
|
if (typeof(T).IsAssignableFrom(task.GetType())) {
|
|
taskList.Add((T)task);
|
|
}
|
|
|
|
ParentTask parentTask;
|
|
if ((parentTask = task as ParentTask) != null) {
|
|
if (parentTask.Children != null) {
|
|
for (int i = 0; i < parentTask.Children.Count; ++i) {
|
|
FindTasks<T>(parentTask.Children[i], ref taskList);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public Task FindTaskWithName(string taskName)
|
|
{
|
|
CheckForSerialization();
|
|
|
|
return FindTaskWithName(taskName, mBehaviorSource.RootTask);
|
|
}
|
|
|
|
private Task FindTaskWithName(string taskName, Task task)
|
|
{
|
|
if (task.FriendlyName.Equals(taskName)) {
|
|
return task;
|
|
}
|
|
|
|
ParentTask parentTask;
|
|
if ((parentTask = task as ParentTask) != null) {
|
|
if (parentTask.Children != null) {
|
|
for (int i = 0; i < parentTask.Children.Count; ++i) {
|
|
Task foundTask = null;
|
|
if ((foundTask = FindTaskWithName(taskName, parentTask.Children[i])) != null) {
|
|
return foundTask;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public List<Task> FindTasksWithName(string taskName)
|
|
{
|
|
CheckForSerialization();
|
|
|
|
List<Task> tasks = new List<Task>();
|
|
FindTasksWithName(taskName, mBehaviorSource.RootTask, ref tasks);
|
|
return tasks;
|
|
}
|
|
|
|
private void FindTasksWithName(string taskName, Task task, ref List<Task> taskList)
|
|
{
|
|
if (task.FriendlyName.Equals(taskName)) {
|
|
taskList.Add(task);
|
|
}
|
|
|
|
ParentTask parentTask;
|
|
if ((parentTask = task as ParentTask) != null) {
|
|
if (parentTask.Children != null) {
|
|
for (int i = 0; i < parentTask.Children.Count; ++i) {
|
|
FindTasksWithName(taskName, parentTask.Children[i], ref taskList);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public List<Task> GetActiveTasks()
|
|
{
|
|
if (BehaviorManager.instance == null) {
|
|
return null;
|
|
}
|
|
return BehaviorManager.instance.GetActiveTasks(this);
|
|
}
|
|
|
|
// System.objects don't normally support coroutines. Add that support here.
|
|
public Coroutine StartTaskCoroutine(Task task, string methodName)
|
|
{
|
|
#if !UNITY_EDITOR && (UNITY_WSA_8_0 || UNITY_WSA_8_1)
|
|
var method = task.GetType().GetMethod(methodName, System.BindingFlags.Public |System.BindingFlags.NonPublic | System.BindingFlags.Instance);
|
|
#else
|
|
var method = task.GetType().GetMethod(methodName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
|
#endif
|
|
if (method == null) {
|
|
Debug.LogError("Unable to start coroutine " + methodName + ": method not found");
|
|
return null;
|
|
}
|
|
if (activeTaskCoroutines == null) {
|
|
activeTaskCoroutines = new Dictionary<string, List<TaskCoroutine>>();
|
|
}
|
|
var taskCoroutine = new TaskCoroutine(this, (IEnumerator)method.Invoke(task, new object[] { }), methodName);
|
|
if (activeTaskCoroutines.ContainsKey(methodName)) {
|
|
var taskCoroutines = activeTaskCoroutines[methodName];
|
|
taskCoroutines.Add(taskCoroutine);
|
|
activeTaskCoroutines[methodName] = taskCoroutines;
|
|
} else {
|
|
var taskCoroutines = new List<TaskCoroutine>();
|
|
taskCoroutines.Add(taskCoroutine);
|
|
activeTaskCoroutines.Add(methodName, taskCoroutines);
|
|
}
|
|
return taskCoroutine.Coroutine;
|
|
}
|
|
|
|
public Coroutine StartTaskCoroutine(Task task, string methodName, object value)
|
|
{
|
|
#if !UNITY_EDITOR && (UNITY_WSA_8_0 || UNITY_WSA_8_1)
|
|
var method = task.GetType().GetMethod(methodName, System.BindingFlags.Public |System.BindingFlags.NonPublic | System.BindingFlags.Instance);
|
|
#else
|
|
var method = task.GetType().GetMethod(methodName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
|
#endif
|
|
if (method == null) {
|
|
Debug.LogError("Unable to start coroutine " + methodName + ": method not found");
|
|
return null;
|
|
}
|
|
if (activeTaskCoroutines == null) {
|
|
activeTaskCoroutines = new Dictionary<string, List<TaskCoroutine>>();
|
|
}
|
|
var taskCoroutine = new TaskCoroutine(this, (IEnumerator)method.Invoke(task, new object[] { value }), methodName);
|
|
if (activeTaskCoroutines.ContainsKey(methodName)) {
|
|
var taskCoroutines = activeTaskCoroutines[methodName];
|
|
taskCoroutines.Add(taskCoroutine);
|
|
activeTaskCoroutines[methodName] = taskCoroutines;
|
|
} else {
|
|
var taskCoroutines = new List<TaskCoroutine>();
|
|
taskCoroutines.Add(taskCoroutine);
|
|
activeTaskCoroutines.Add(methodName, taskCoroutines);
|
|
}
|
|
return taskCoroutine.Coroutine;
|
|
}
|
|
|
|
public void StopTaskCoroutine(string methodName)
|
|
{
|
|
if (!activeTaskCoroutines.ContainsKey(methodName)) {
|
|
return;
|
|
}
|
|
|
|
var taskCoroutines = activeTaskCoroutines[methodName];
|
|
for (int i = 0; i < taskCoroutines.Count; ++i) {
|
|
taskCoroutines[i].Stop();
|
|
}
|
|
}
|
|
|
|
public void StopAllTaskCoroutines()
|
|
{
|
|
StopAllCoroutines();
|
|
|
|
if (activeTaskCoroutines == null) {
|
|
return;
|
|
}
|
|
|
|
foreach (var entry in activeTaskCoroutines) {
|
|
var taskCoroutines = entry.Value;
|
|
for (int i = 0; i < taskCoroutines.Count; ++i) {
|
|
taskCoroutines[i].Stop();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void TaskCoroutineEnded(TaskCoroutine taskCoroutine, string coroutineName)
|
|
{
|
|
if (activeTaskCoroutines.ContainsKey(coroutineName)) {
|
|
var taskCoroutines = activeTaskCoroutines[coroutineName];
|
|
if (taskCoroutines.Count == 1) {
|
|
activeTaskCoroutines.Remove(coroutineName);
|
|
} else {
|
|
taskCoroutines.Remove(taskCoroutine);
|
|
activeTaskCoroutines[coroutineName] = taskCoroutines;
|
|
}
|
|
}
|
|
}
|
|
public void OnBehaviorStarted()
|
|
{
|
|
if (!initialized) {
|
|
CheckForEventMethods(new HashSet<Task>(), mBehaviorSource.RootTask);
|
|
initialized = true;
|
|
}
|
|
|
|
if (OnBehaviorStart != null) {
|
|
OnBehaviorStart(this);
|
|
}
|
|
}
|
|
|
|
private void CheckForEventMethods(HashSet<Task> tasksChecked, Task task)
|
|
{
|
|
if (task == null) {
|
|
return;
|
|
}
|
|
|
|
if (!tasksChecked.Contains(task)) {
|
|
#if !UNITY_EDITOR && (UNITY_WSA_8_0 || UNITY_WSA_8_1)
|
|
var method = task.GetType().GetMethods(System.BindingFlags.Public |System.BindingFlags.NonPublic | System.BindingFlags.Instance | System.BindingFlags.DeclaredOnly);
|
|
#else
|
|
var methods = task.GetType().GetMethods(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.DeclaredOnly);
|
|
#endif
|
|
if (methods != null) {
|
|
for (int i = 0; i < (int)EventTypes.None; ++i) {
|
|
if (hasEvent[i]) {
|
|
continue;
|
|
}
|
|
|
|
var methodName = ((EventTypes)i).ToString();
|
|
for (int j = 0; j < methods.Length; ++j) {
|
|
hasEvent[i] = methods[j].Name.Equals(methodName);
|
|
if (hasEvent[i]) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (task is ParentTask) {
|
|
var parentTask = task as ParentTask;
|
|
if (parentTask.Children != null) {
|
|
for (int i = 0; i < parentTask.Children.Count; ++i) {
|
|
CheckForEventMethods(tasksChecked, parentTask.Children[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void OnBehaviorRestarted()
|
|
{
|
|
if (OnBehaviorRestart != null) {
|
|
OnBehaviorRestart(this);
|
|
}
|
|
}
|
|
|
|
public void OnBehaviorEnded()
|
|
{
|
|
if (OnBehaviorEnd != null) {
|
|
OnBehaviorEnd(this);
|
|
}
|
|
}
|
|
|
|
private void RegisterEvent(string name, Delegate handler)
|
|
{
|
|
if (eventTable == null) {
|
|
eventTable = new Dictionary<Type, Dictionary<string, Delegate>>();
|
|
}
|
|
|
|
Dictionary<string, Delegate> eventHandlers;
|
|
if (!eventTable.TryGetValue(handler.GetType(), out eventHandlers)) {
|
|
eventHandlers = new Dictionary<string, Delegate>();
|
|
eventTable.Add(handler.GetType(), eventHandlers);
|
|
}
|
|
|
|
Delegate prevHandlers;
|
|
if (eventHandlers.TryGetValue(name, out prevHandlers)) {
|
|
eventHandlers[name] = Delegate.Combine(prevHandlers, handler);
|
|
} else {
|
|
eventHandlers.Add(name, handler);
|
|
}
|
|
}
|
|
|
|
public void RegisterEvent(string name, System.Action handler)
|
|
{
|
|
RegisterEvent(name, (Delegate)handler);
|
|
}
|
|
|
|
public void RegisterEvent<T>(string name, System.Action<T> handler)
|
|
{
|
|
RegisterEvent(name, (Delegate)handler);
|
|
}
|
|
|
|
public void RegisterEvent<T, U>(string name, System.Action<T, U> handler)
|
|
{
|
|
RegisterEvent(name, (Delegate)handler);
|
|
}
|
|
|
|
public void RegisterEvent<T, U, V>(string name, System.Action<T, U, V> handler)
|
|
{
|
|
RegisterEvent(name, (Delegate)handler);
|
|
}
|
|
|
|
private Delegate GetDelegate(string name, Type type)
|
|
{
|
|
Dictionary<string, Delegate> eventHandlers;
|
|
if (eventTable != null && eventTable.TryGetValue(type, out eventHandlers)) {
|
|
Delegate handler;
|
|
if (eventHandlers.TryGetValue(name, out handler)) {
|
|
return handler;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public void SendEvent(string name)
|
|
{
|
|
var handler = GetDelegate(name, typeof(System.Action)) as System.Action;
|
|
if (handler != null) {
|
|
handler();
|
|
}
|
|
}
|
|
|
|
public void SendEvent<T>(string name, T arg1)
|
|
{
|
|
var handler = GetDelegate(name, typeof(System.Action<T>)) as System.Action<T>;
|
|
if (handler != null) {
|
|
handler(arg1);
|
|
}
|
|
}
|
|
|
|
public void SendEvent<T, U>(string name, T arg1, U arg2)
|
|
{
|
|
var handler = GetDelegate(name, typeof(System.Action<T, U>)) as System.Action<T, U>;
|
|
if (handler != null) {
|
|
handler(arg1, arg2);
|
|
}
|
|
}
|
|
|
|
public void SendEvent<T, U, V>(string name, T arg1, U arg2, V arg3)
|
|
{
|
|
var handler = GetDelegate(name, typeof(System.Action<T, U, V>)) as System.Action<T, U, V>;
|
|
if (handler != null) {
|
|
handler(arg1, arg2, arg3);
|
|
}
|
|
}
|
|
|
|
private void UnregisterEvent(string name, Delegate handler)
|
|
{
|
|
if (eventTable == null) {
|
|
return;
|
|
}
|
|
Dictionary<string, Delegate> eventHandlers;
|
|
if (eventTable.TryGetValue(handler.GetType(), out eventHandlers)) {
|
|
Delegate prevHandlers;
|
|
if (eventHandlers.TryGetValue(name, out prevHandlers)) {
|
|
eventHandlers[name] = Delegate.Remove(prevHandlers, handler);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void UnregisterEvent(string name, System.Action handler)
|
|
{
|
|
UnregisterEvent(name, (Delegate)handler);
|
|
}
|
|
|
|
public void UnregisterEvent<T>(string name, System.Action<T> handler)
|
|
{
|
|
UnregisterEvent(name, (Delegate)handler);
|
|
}
|
|
|
|
public void UnregisterEvent<T, U>(string name, System.Action<T, U> handler)
|
|
{
|
|
UnregisterEvent(name, (Delegate)handler);
|
|
}
|
|
|
|
public void UnregisterEvent<T, U, V>(string name, System.Action<T, U, V> handler)
|
|
{
|
|
UnregisterEvent(name, (Delegate)handler);
|
|
}
|
|
|
|
public void SaveResetValues()
|
|
{
|
|
if (defaultValues == null) {
|
|
CheckForSerialization();
|
|
|
|
defaultValues = new Dictionary<Task, Dictionary<string, object>>();
|
|
defaultVariableValues = new Dictionary<SharedVariable, object>();
|
|
|
|
SaveValues();
|
|
} else {
|
|
ResetValues();
|
|
}
|
|
}
|
|
|
|
private void SaveValues()
|
|
{
|
|
var variables = mBehaviorSource.GetAllVariables();
|
|
if (variables != null) {
|
|
for (int i = 0; i < variables.Count; ++i) {
|
|
defaultVariableValues.Add(variables[i], variables[i].GetValue());
|
|
}
|
|
}
|
|
|
|
SaveValue(mBehaviorSource.RootTask);
|
|
}
|
|
|
|
private void SaveValue(Task task)
|
|
{
|
|
if (task == null) {
|
|
return;
|
|
}
|
|
|
|
var fields = TaskUtility.GetPublicFields(task.GetType());
|
|
var taskValues = new Dictionary<string, object>();
|
|
for (int i = 0; i < fields.Length; ++i) {
|
|
var value = fields[i].GetValue(task);
|
|
if (value is SharedVariable) {
|
|
var sharedVariable = value as SharedVariable;
|
|
if (sharedVariable.IsGlobal || sharedVariable.IsShared) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
taskValues.Add(fields[i].Name, fields[i].GetValue(task));
|
|
}
|
|
|
|
defaultValues.Add(task, taskValues);
|
|
|
|
if (task is ParentTask) {
|
|
var parentTask = task as ParentTask;
|
|
if (parentTask.Children != null) {
|
|
for (int i = 0; i < parentTask.Children.Count; ++i) {
|
|
SaveValue(parentTask.Children[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ResetValues()
|
|
{
|
|
foreach (var variableValue in defaultVariableValues) {
|
|
SetVariableValue(variableValue.Key.Name, variableValue.Value);
|
|
}
|
|
|
|
ResetValue(mBehaviorSource.RootTask);
|
|
}
|
|
|
|
private void ResetValue(Task task)
|
|
{
|
|
if (task == null) {
|
|
return;
|
|
}
|
|
|
|
Dictionary<string, object> taskValues;
|
|
if (!defaultValues.TryGetValue(task, out taskValues)) {
|
|
return;
|
|
}
|
|
|
|
foreach (var taskValue in taskValues) {
|
|
var field = task.GetType().GetField(taskValue.Key);
|
|
if (field != null) {
|
|
field.SetValue(task, taskValue.Value);
|
|
}
|
|
}
|
|
|
|
if (task is ParentTask) {
|
|
var parentTask = task as ParentTask;
|
|
if (parentTask.Children != null) {
|
|
for (int i = 0; i < parentTask.Children.Count; ++i) {
|
|
ResetValue(parentTask.Children[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return mBehaviorSource.ToString();
|
|
}
|
|
|
|
public static BehaviorManager CreateBehaviorManager()
|
|
{
|
|
if (BehaviorManager.instance == null && Application.isPlaying) {
|
|
var behaviorManager = new GameObject();
|
|
//behaviorManager.hideFlags = HideFlags.HideAndDontSave;
|
|
behaviorManager.name = "Behavior Manager";
|
|
return behaviorManager.AddComponent<BehaviorManager>();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reset the static variables for domain reloading.
|
|
/// </summary>
|
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
|
private static void DomainReset()
|
|
{
|
|
#if UNITY_2023_1_OR_NEWER
|
|
var behaviors = UnityEngine.Object.FindObjectsByType<Behavior>(FindObjectsSortMode.None);
|
|
#else
|
|
var behaviors = UnityEngine.Object.FindObjectsOfType<Behavior>();
|
|
#endif
|
|
if (behaviors == null) {
|
|
return;
|
|
}
|
|
for (int i = 0; i < behaviors.Length; ++i) {
|
|
behaviors[i].mBehaviorSource.HasSerialized = false;
|
|
}
|
|
}
|
|
}
|
|
} |