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> defaultValues; private Dictionary 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> activeTaskCoroutines = null; // events public delegate void BehaviorHandler(Behavior behavior); public event BehaviorHandler OnBehaviorStart; public event BehaviorHandler OnBehaviorRestart; public event BehaviorHandler OnBehaviorEnd; private Dictionary> 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 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() where T : Task { CheckForSerialization(); return FindTask(mBehaviorSource.RootTask); } private T FindTask(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(parentTask.Children[i])) != null) { return foundTask; } } } } return null; } public List FindTasks() where T : Task { CheckForSerialization(); List tasks = new List(); FindTasks(mBehaviorSource.RootTask, ref tasks); return tasks; } private void FindTasks(Task task, ref List 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(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 FindTasksWithName(string taskName) { CheckForSerialization(); List tasks = new List(); FindTasksWithName(taskName, mBehaviorSource.RootTask, ref tasks); return tasks; } private void FindTasksWithName(string taskName, Task task, ref List 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 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>(); } 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(); 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>(); } 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(); 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(), mBehaviorSource.RootTask); initialized = true; } if (OnBehaviorStart != null) { OnBehaviorStart(this); } } private void CheckForEventMethods(HashSet 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>(); } Dictionary eventHandlers; if (!eventTable.TryGetValue(handler.GetType(), out eventHandlers)) { eventHandlers = new Dictionary(); 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(string name, System.Action handler) { RegisterEvent(name, (Delegate)handler); } public void RegisterEvent(string name, System.Action handler) { RegisterEvent(name, (Delegate)handler); } public void RegisterEvent(string name, System.Action handler) { RegisterEvent(name, (Delegate)handler); } private Delegate GetDelegate(string name, Type type) { Dictionary 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(string name, T arg1) { var handler = GetDelegate(name, typeof(System.Action)) as System.Action; if (handler != null) { handler(arg1); } } public void SendEvent(string name, T arg1, U arg2) { var handler = GetDelegate(name, typeof(System.Action)) as System.Action; if (handler != null) { handler(arg1, arg2); } } public void SendEvent(string name, T arg1, U arg2, V arg3) { var handler = GetDelegate(name, typeof(System.Action)) as System.Action; if (handler != null) { handler(arg1, arg2, arg3); } } private void UnregisterEvent(string name, Delegate handler) { if (eventTable == null) { return; } Dictionary 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(string name, System.Action handler) { UnregisterEvent(name, (Delegate)handler); } public void UnregisterEvent(string name, System.Action handler) { UnregisterEvent(name, (Delegate)handler); } public void UnregisterEvent(string name, System.Action handler) { UnregisterEvent(name, (Delegate)handler); } public void SaveResetValues() { if (defaultValues == null) { CheckForSerialization(); defaultValues = new Dictionary>(); defaultVariableValues = new Dictionary(); 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(); 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 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(); } return null; } /// /// Reset the static variables for domain reloading. /// [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] private static void DomainReset() { #if UNITY_2023_1_OR_NEWER var behaviors = UnityEngine.Object.FindObjectsByType(FindObjectsSortMode.None); #else var behaviors = UnityEngine.Object.FindObjectsOfType(); #endif if (behaviors == null) { return; } for (int i = 0; i < behaviors.Length; ++i) { behaviors[i].mBehaviorSource.HasSerialized = false; } } } }