using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using BehaviorDesigner.Runtime.Tasks; using UnityEngine; namespace BehaviorDesigner.Runtime { [Serializable] public abstract class Behavior : MonoBehaviour, IBehavior { public enum GizmoViewMode { Running = 0, Always = 1, Selected = 2, Never = 3 } public delegate void BehaviorHandler(); [NonSerialized] public UpdateIntervalType UpdateInterval; [NonSerialized] public float UpdateIntervalSeconds; [NonSerialized] public float LastUpdateTime; [NonSerialized] public bool DisableBehaviorWhenMonoDisabled = true; [NonSerialized] public bool TryEnableBehaviorWhenMonoEnabled = true; [SerializeField] private bool startWhenEnabled = true; [SerializeField] private bool pauseWhenDisabled; [SerializeField] private bool restartWhenComplete; [SerializeField] private bool logTaskChanges; [SerializeField] private int group; [SerializeField] private bool resetValuesOnRestart; [SerializeField] private ExternalBehavior externalBehavior; private bool hasInheritedVariables; [SerializeField] private BehaviorSource mBehaviorSource; private bool isPaused; private TaskStatus executionStatus; private bool initialized; private List> defaultValues; private Dictionary defaultVariableValues; private Dictionary> activeTaskCoroutines; private Dictionary> eventTable; [NonSerialized] public bool selected; [NonSerialized] public GizmoViewMode gizmoViewMode; [NonSerialized] public bool showBehaviorDesignerGizmo = true; public bool StartWhenEnabled { get { return startWhenEnabled; } set { startWhenEnabled = value; } } public bool PauseWhenDisabled { get { return pauseWhenDisabled; } set { pauseWhenDisabled = value; } } public bool RestartWhenComplete { get { return restartWhenComplete; } set { restartWhenComplete = value; } } public bool LogTaskChanges { get { return logTaskChanges; } set { logTaskChanges = value; } } public int Group { get { return group; } set { group = value; } } public bool ResetValuesOnRestart { get { return resetValuesOnRestart; } set { resetValuesOnRestart = value; } } public ExternalBehavior ExternalBehavior { get { return externalBehavior; } set { if (externalBehavior != value) { if (BehaviorManager.instance != null) { BehaviorManager.instance.DisableBehavior(this); } mBehaviorSource.HasSerialized = false; } externalBehavior = value; if (startWhenEnabled) { EnableBehavior(); } } } 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; } } public TaskStatus ExecutionStatus { get { return executionStatus; } set { executionStatus = value; } } public event BehaviorHandler OnBehaviorStart; public event BehaviorHandler OnBehaviorRestart; public event BehaviorHandler OnBehaviorEnd; public Behavior() { mBehaviorSource = new BehaviorSource(this); } public BehaviorSource GetBehaviorSource() { return mBehaviorSource; } public void SetBehaviorSource(BehaviorSource behaviorSource) { mBehaviorSource = behaviorSource; } public UnityEngine.Object GetObject() { return this; } public string GetOwnerName() { return base.gameObject.name; } public void OnDrawGizmosSelected() { if (showBehaviorDesignerGizmo) { Gizmos.DrawIcon(base.transform.position, "Behavior Designer Scene Icon.png"); } } public void Start() { if (startWhenEnabled) { EnableBehavior(); } initialized = true; } private bool TaskContainsMethod(string methodName, Task task) { if (task == null) { return false; } MethodInfo method = task.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null && task.GetType().Equals(method.DeclaringType)) { return true; } if (task is ParentTask) { ParentTask parentTask = task as ParentTask; if (parentTask.Children != null) { for (int i = 0; i < parentTask.Children.Count; i++) { if (TaskContainsMethod(methodName, parentTask.Children[i])) { return true; } } } } return false; } public void EnableBehavior() { 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 (TryEnableBehaviorWhenMonoEnabled) { if (BehaviorManager.instance != null && isPaused) { BehaviorManager.instance.EnableBehavior(this); isPaused = false; } else if (startWhenEnabled && initialized) { EnableBehavior(); } } } public void OnDisable() { if (DisableBehaviorWhenMonoDisabled) { DisableBehavior(); } } 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) { SharedVariable variable = GetVariable(name); if (variable != null) { variable.SetValue(value); variable.ValueChanged(); } } public List GetAllVariables() { CheckForSerialization(); return mBehaviorSource.GetAllVariables(); } public void CheckForSerialization() { if (externalBehavior != null) { List list = null; bool force = false; if (!hasInheritedVariables) { mBehaviorSource.CheckForSerialization(false); list = mBehaviorSource.GetAllVariables(); hasInheritedVariables = true; force = true; } externalBehavior.BehaviorSource.Owner = ExternalBehavior; externalBehavior.BehaviorSource.CheckForSerialization(force, GetBehaviorSource()); if (list == null) { return; } for (int i = 0; i < list.Count; i++) { if (list[i] != null) { mBehaviorSource.SetVariable(list[i].Name, list[i]); } } } else { mBehaviorSource.CheckForSerialization(false); } } public void OnDrawGizmos() { if (gizmoViewMode == GizmoViewMode.Never || (gizmoViewMode == GizmoViewMode.Selected && !selected) || (gizmoViewMode != GizmoViewMode.Running && gizmoViewMode != GizmoViewMode.Always && (!Application.isPlaying || ExecutionStatus != TaskStatus.Running) && Application.isPlaying)) { return; } CheckForSerialization(); OnDrawGizmos(mBehaviorSource.RootTask); List detachedTasks = mBehaviorSource.DetachedTasks; if (detachedTasks != null) { for (int i = 0; i < detachedTasks.Count; i++) { OnDrawGizmos(detachedTasks[i]); } } } private void OnDrawGizmos(Task task) { if (task == null || (gizmoViewMode == GizmoViewMode.Running && !task.NodeData.IsReevaluating && (task.NodeData.IsReevaluating || task.NodeData.ExecutionStatus != TaskStatus.Running))) { return; } task.OnDrawGizmos(); if (!(task is ParentTask)) { return; } ParentTask parentTask = task as ParentTask; if (parentTask.Children != null) { for (int i = 0; i < parentTask.Children.Count; i++) { OnDrawGizmos(parentTask.Children[i]); } } } public T FindTask() where T : Task { 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 && parentTask.Children != null) { for (int i = 0; i < parentTask.Children.Count; i++) { T val = (T)null; if ((val = FindTask(parentTask.Children[i])) != null) { return val; } } } return (T)null; } public List FindTasks() where T : Task { List taskList = new List(); FindTasks(mBehaviorSource.RootTask, ref taskList); return taskList; } 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 && parentTask.Children != null) { for (int i = 0; i < parentTask.Children.Count; i++) { FindTasks(parentTask.Children[i], ref taskList); } } } public Task FindTaskWithName(string taskName) { 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 && parentTask.Children != null) { for (int i = 0; i < parentTask.Children.Count; i++) { Task task2 = null; if ((task2 = FindTaskWithName(taskName, parentTask.Children[i])) != null) { return task2; } } } return null; } public List FindTasksWithName(string taskName) { List taskList = new List(); FindTasksWithName(taskName, mBehaviorSource.RootTask, ref taskList); return taskList; } 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 && 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); } public Coroutine StartTaskCoroutine(Task task, string methodName) { MethodInfo method = task.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { Debug.LogError("Unable to start coroutine " + methodName + ": method not found"); return null; } if (activeTaskCoroutines == null) { activeTaskCoroutines = new Dictionary>(); } TaskCoroutine taskCoroutine = new TaskCoroutine(this, (IEnumerator)method.Invoke(task, new object[0]), methodName); if (activeTaskCoroutines.ContainsKey(methodName)) { List list = activeTaskCoroutines[methodName]; list.Add(taskCoroutine); activeTaskCoroutines[methodName] = list; } else { List list2 = new List(); list2.Add(taskCoroutine); activeTaskCoroutines.Add(methodName, list2); } return taskCoroutine.Coroutine; } public Coroutine StartTaskCoroutine(Task task, string methodName, object value) { MethodInfo method = task.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { Debug.LogError("Unable to start coroutine " + methodName + ": method not found"); return null; } if (activeTaskCoroutines == null) { activeTaskCoroutines = new Dictionary>(); } TaskCoroutine taskCoroutine = new TaskCoroutine(this, (IEnumerator)method.Invoke(task, new object[1] { value }), methodName); if (activeTaskCoroutines.ContainsKey(methodName)) { List list = activeTaskCoroutines[methodName]; list.Add(taskCoroutine); activeTaskCoroutines[methodName] = list; } else { List list2 = new List(); list2.Add(taskCoroutine); activeTaskCoroutines.Add(methodName, list2); } return taskCoroutine.Coroutine; } public void StopTaskCoroutine(string methodName) { if (activeTaskCoroutines.ContainsKey(methodName)) { List list = activeTaskCoroutines[methodName]; for (int i = 0; i < list.Count; i++) { list[i].Stop(); } } } public void StopAllTaskCoroutines() { StopAllCoroutines(); foreach (KeyValuePair> activeTaskCoroutine in activeTaskCoroutines) { List value = activeTaskCoroutine.Value; for (int i = 0; i < value.Count; i++) { value[i].Stop(); } } } public void TaskCoroutineEnded(TaskCoroutine taskCoroutine, string coroutineName) { if (activeTaskCoroutines.ContainsKey(coroutineName)) { List list = activeTaskCoroutines[coroutineName]; if (list.Count == 1) { activeTaskCoroutines.Remove(coroutineName); return; } list.Remove(taskCoroutine); activeTaskCoroutines[coroutineName] = list; } } public void OnBehaviorStarted() { if (this.OnBehaviorStart != null) { this.OnBehaviorStart(); } } public void OnBehaviorRestarted() { if (this.OnBehaviorRestart != null) { this.OnBehaviorRestart(); } } public void OnBehaviorEnded() { if (this.OnBehaviorEnd != null) { this.OnBehaviorEnd(); } } private void RegisterEvent(string name, Delegate handler) { if (eventTable == null) { eventTable = new Dictionary>(); } Dictionary value; if (!eventTable.TryGetValue(handler.GetType(), out value)) { value = new Dictionary(); eventTable.Add(handler.GetType(), value); } Delegate value2; if (value.TryGetValue(name, out value2)) { value[name] = Delegate.Combine(value2, handler); } else { value.Add(name, handler); } } public void RegisterEvent(string name, System.Action handler) { RegisterEvent(name, (Delegate)handler); } public void RegisterEvent(string name, Action handler) { RegisterEvent(name, (Delegate)handler); } public void RegisterEvent(string name, Action handler) { RegisterEvent(name, (Delegate)handler); } public void RegisterEvent(string name, Action handler) { RegisterEvent(name, (Delegate)handler); } private Delegate GetDelegate(string name, Type type) { Dictionary value; Delegate value2; if (eventTable != null && eventTable.TryGetValue(type, out value) && value.TryGetValue(name, out value2)) { return value2; } return null; } public void SendEvent(string name) { System.Action action = GetDelegate(name, typeof(System.Action)) as System.Action; if (action != null) { action(); } } public void SendEvent(string name, T arg1) { Action action = GetDelegate(name, typeof(Action)) as Action; if (action != null) { action(arg1); } } public void SendEvent(string name, T arg1, U arg2) { Action action = GetDelegate(name, typeof(Action)) as Action; if (action != null) { action(arg1, arg2); } } public void SendEvent(string name, T arg1, U arg2, V arg3) { Action action = GetDelegate(name, typeof(Action)) as Action; if (action != null) { action(arg1, arg2, arg3); } } private void UnregisterEvent(string name, Delegate handler) { Dictionary value; Delegate value2; if (eventTable != null && eventTable.TryGetValue(handler.GetType(), out value) && value.TryGetValue(name, out value2)) { value[name] = Delegate.Remove(value2, handler); } } public void UnregisterEvent(string name, System.Action handler) { UnregisterEvent(name, (Delegate)handler); } public void UnregisterEvent(string name, Action handler) { UnregisterEvent(name, (Delegate)handler); } public void UnregisterEvent(string name, Action handler) { UnregisterEvent(name, (Delegate)handler); } public void UnregisterEvent(string name, Action handler) { UnregisterEvent(name, (Delegate)handler); } public void SaveResetValues() { if (defaultValues == null) { defaultValues = new List>(); defaultVariableValues = new Dictionary(); SaveValues(); } else { ResetValues(); } } private void SaveValues() { List allVariables = mBehaviorSource.GetAllVariables(); for (int i = 0; i < allVariables.Count; i++) { defaultVariableValues.Add(allVariables[i].Name, allVariables[i].GetValue()); } SaveValue(mBehaviorSource.RootTask); } private void SaveValue(Task task) { if (task == null) { return; } FieldInfo[] publicFields = TaskUtility.GetPublicFields(task.GetType()); Dictionary dictionary = new Dictionary(); for (int i = 0; i < publicFields.Length; i++) { object value = publicFields[i].GetValue(task); if (value is SharedVariable) { SharedVariable sharedVariable = value as SharedVariable; if (sharedVariable.IsGlobal || sharedVariable.IsShared) { continue; } } dictionary.Add(publicFields[i].Name, publicFields[i].GetValue(task)); } defaultValues.Add(dictionary); if (!(task is ParentTask)) { return; } ParentTask parentTask = task as ParentTask; if (parentTask.Children != null) { for (int j = 0; j < parentTask.Children.Count; j++) { SaveValue(parentTask.Children[j]); } } } private void ResetValues() { foreach (KeyValuePair defaultVariableValue in defaultVariableValues) { SetVariableValue(defaultVariableValue.Key, defaultVariableValue.Value); } int index = 0; ResetValue(mBehaviorSource.RootTask, ref index); } private void ResetValue(Task task, ref int index) { if (task == null) { return; } Dictionary dictionary = defaultValues[index]; index++; foreach (KeyValuePair item in dictionary) { FieldInfo field = task.GetType().GetField(item.Key); if (field != null) { field.SetValue(task, item.Value); } } if (!(task is ParentTask)) { return; } ParentTask parentTask = task as ParentTask; if (parentTask.Children != null) { for (int i = 0; i < parentTask.Children.Count; i++) { ResetValue(parentTask.Children[i], ref index); } } } public override string ToString() { return mBehaviorSource.ToString(); } public static BehaviorManager CreateBehaviorManager() { if (BehaviorManager.instance == null && Application.isPlaying) { GameObject gameObject = new GameObject(); gameObject.name = "Behavior Manager"; return gameObject.AddComponent(); } return null; } int IBehavior.GetInstanceID() { return GetInstanceID(); } } }