tanghai 8 лет назад
Родитель
Сommit
56ff7d9f9a
100 измененных файлов с 5225 добавлено и 0 удалено
  1. 9 0
      Unity/Assets/Editor/BehaviorTreeEditor.meta
  2. 88 0
      Unity/Assets/Editor/BehaviorTreeEditor/BTBatchOperation.cs
  3. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/BTBatchOperation.cs.meta
  4. 40 0
      Unity/Assets/Editor/BehaviorTreeEditor/BTDesignerUtility.cs
  5. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/BTDesignerUtility.cs.meta
  6. 168 0
      Unity/Assets/Editor/BehaviorTreeEditor/BTEditorWindow.cs
  7. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/BTEditorWindow.cs.meta
  8. 613 0
      Unity/Assets/Editor/BehaviorTreeEditor/BTEntity.cs
  9. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/BTEntity.cs.meta
  10. 67 0
      Unity/Assets/Editor/BehaviorTreeEditor/BehaviorNodeConfigExtension.cs
  11. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/BehaviorNodeConfigExtension.cs.meta
  12. 118 0
      Unity/Assets/Editor/BehaviorTreeEditor/BehaviorNodeData.cs
  13. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/BehaviorNodeData.cs.meta
  14. 22 0
      Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeConfigEditor.cs
  15. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeConfigEditor.cs.meta
  16. 56 0
      Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeConfigExtension.cs
  17. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeConfigExtension.cs.meta
  18. 42 0
      Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeData.cs
  19. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeData.cs.meta
  20. 22 0
      Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeMenu.cs
  21. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeMenu.cs.meta
  22. 159 0
      Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeNodeClassPopup.cs
  23. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeNodeClassPopup.cs.meta
  24. 157 0
      Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeOperateUtility.cs
  25. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeOperateUtility.cs.meta
  26. 13 0
      Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeTipsHelper.cs
  27. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeTipsHelper.cs.meta
  28. 242 0
      Unity/Assets/Editor/BehaviorTreeEditor/CustomArrayField.cs
  29. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/CustomArrayField.cs.meta
  30. 9 0
      Unity/Assets/Editor/BehaviorTreeEditor/Event.meta
  31. 14 0
      Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeAfterChangeNodeTypeEvent_SelectNode.cs
  32. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeAfterChangeNodeTypeEvent_SelectNode.cs.meta
  33. 13 0
      Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeClickNodeEvent_SelectNode.cs
  34. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeClickNodeEvent_SelectNode.cs.meta
  35. 13 0
      Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeConnectStateEvent_HandleConnectLines.cs
  36. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeConnectStateEvent_HandleConnectLines.cs.meta
  37. 13 0
      Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeCreateNodeEvent_SelectNode.cs
  38. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeCreateNodeEvent_SelectNode.cs.meta
  39. 13 0
      Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeMouseInNodeEvent_HandleOperate.cs
  40. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeMouseInNodeEvent_HandleOperate.cs.meta
  41. 14 0
      Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeNewCreateClickEvent_CreateNode.cs
  42. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeNewCreateClickEvent_CreateNode.cs.meta
  43. 20 0
      Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeOpenEditorEvent_SelectNode.cs
  44. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeOpenEditorEvent_SelectNode.cs.meta
  45. 13 0
      Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeOpenEditorEvent_SelectTree.cs
  46. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeOpenEditorEvent_SelectTree.cs.meta
  47. 13 0
      Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeOpenEditorEvent_UpdatePropList.cs
  48. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeOpenEditorEvent_UpdatePropList.cs.meta
  49. 14 0
      Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeReplaceClickEvent_ReplaceNode.cs
  50. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeReplaceClickEvent_ReplaceNode.cs.meta
  51. 13 0
      Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeRightDesignerDragEvent_ModifyRightBorder.cs
  52. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeRightDesignerDragEvent_ModifyRightBorder.cs.meta
  53. 20 0
      Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeRunTreeEvent_ShowDebugInfo.cs
  54. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeRunTreeEvent_ShowDebugInfo.cs.meta
  55. 160 0
      Unity/Assets/Editor/BehaviorTreeEditor/FoldoutNode.cs
  56. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/FoldoutNode.cs.meta
  57. 782 0
      Unity/Assets/Editor/BehaviorTreeEditor/GraphDesigner.cs
  58. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/GraphDesigner.cs.meta
  59. 354 0
      Unity/Assets/Editor/BehaviorTreeEditor/NodeDesigner.cs
  60. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/NodeDesigner.cs.meta
  61. 290 0
      Unity/Assets/Editor/BehaviorTreeEditor/NodeExtension.cs
  62. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/NodeExtension.cs.meta
  63. 37 0
      Unity/Assets/Editor/BehaviorTreeEditor/NodeMeta.cs
  64. 270 0
      Unity/Assets/Editor/BehaviorTreeEditor/NodeMetaHelper.cs
  65. 12 0
      Unity/Assets/Editor/BehaviorTreeEditor/NodeMetaHelper.cs.meta
  66. 9 0
      Unity/Assets/Editor/BehaviorTreeEditor/Pic.meta
  67. BIN
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/Bg.png
  68. 56 0
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/Bg.png.meta
  69. BIN
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/BgLine.png
  70. 56 0
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/BgLine.png.meta
  71. BIN
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/DragIcon.png
  72. 56 0
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/DragIcon.png.meta
  73. BIN
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/Error.png
  74. 56 0
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/Error.png.meta
  75. BIN
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/Execute.png
  76. 57 0
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/Execute.png.meta
  77. BIN
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/False.png
  78. 56 0
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/False.png.meta
  79. BIN
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/HighLight.png
  80. 56 0
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/HighLight.png.meta
  81. BIN
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/LeftConnect.png
  82. 56 0
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/LeftConnect.png.meta
  83. BIN
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/RightConnect.png
  84. 56 0
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/RightConnect.png.meta
  85. BIN
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/SelectHighLight.png
  86. 56 0
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/SelectHighLight.png.meta
  87. BIN
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/ShiftIcon.png
  88. 56 0
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/ShiftIcon.png.meta
  89. BIN
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/True.png
  90. 56 0
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/True.png.meta
  91. BIN
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/blue.png
  92. 56 0
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/blue.png.meta
  93. BIN
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/default.png
  94. 56 0
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/default.png.meta
  95. BIN
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/green.png
  96. 56 0
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/green.png.meta
  97. BIN
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/orange.png
  98. 56 0
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/orange.png.meta
  99. BIN
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/pink.png
  100. 56 0
      Unity/Assets/Editor/BehaviorTreeEditor/Pic/pink.png.meta

+ 9 - 0
Unity/Assets/Editor/BehaviorTreeEditor.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 3a5857cabaf3b664fb4305495ee65ae8
+folderAsset: yes
+timeCreated: 1498181747
+licenseType: Free
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 88 - 0
Unity/Assets/Editor/BehaviorTreeEditor/BTBatchOperation.cs

@@ -0,0 +1,88 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using Model;
+using UnityEditor;
+
+namespace MyEditor
+{
+	public class BTBatchOperation
+	{
+		public delegate void ExcuteTreeOperate(BehaviorTreeConfig treeConfig, string treePath);
+
+		public static Dictionary<int, BehaviorTreeConfig> mId2TreeDict = new Dictionary<int, BehaviorTreeConfig>();
+		public static Dictionary<string, NodeMeta> mCientNodeDict;
+		public static Dictionary<string, bool> mUseNodeDict = new Dictionary<string, bool>();
+
+		public static void HasUseNode(NodeProto node, string treePath)
+		{
+			if (string.IsNullOrEmpty(node.Name))
+			{
+				Log.Error($"node name can not be empty!! {treePath}");
+			}
+			if (!mUseNodeDict.ContainsKey(node.Name))
+			{
+				Log.Warning($"{node.Name} not exist!!!");
+			}
+			else
+			{
+				mUseNodeDict[node.Name] = true;
+			}
+			for (int i = 0; i < node.children.Count; i++)
+			{
+				HasUseNode(node.children[i], treePath);
+			}
+		}
+
+		public static void SaveOneTree(BehaviorTreeConfig treeConfig, string treePath, params object[] paramList)
+		{
+			EditorUtility.SetDirty(treeConfig.gameObject);
+			AssetDatabase.SaveAssets();
+		}
+
+		public static void CheckHasName(BehaviorTreeConfig config, string path, string nodeName)
+		{
+			if (HasNode(config.RootNodeProto, nodeName))
+			{
+				Log.Info($"{nodeName}: {path}");
+			}
+		}
+
+		public static bool HasNode(NodeProto node, string name)
+		{
+			if (node.Name == name)
+			{
+				return true;
+			}
+			for (int i = 0; i < node.children.Count; i++)
+			{
+				if (HasNode(node.children[i], name))
+				{
+					return true;
+				}
+			}
+			return false;
+		}
+
+		public static bool HasNodeField(NodeProto node, Type searchType, string prefabPath)
+		{
+			FieldInfo[] fieldInfos = NodeMetaHelper.GetFieldInfos(node.Name);
+			foreach (FieldInfo fieldInfo in fieldInfos)
+			{
+				if (fieldInfo.FieldType == searchType)
+				{
+					Log.Info($"{prefabPath}");
+					return true;
+				}
+			}
+			for (int i = 0; i < node.children.Count; i++)
+			{
+				if (HasNodeField(node.children[i], searchType, prefabPath))
+				{
+					return true;
+				}
+			}
+			return false;
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/BTBatchOperation.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: efaceecc0d53ec74088acfc8dccc57d1
+timeCreated: 1456310067
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 40 - 0
Unity/Assets/Editor/BehaviorTreeEditor/BTDesignerUtility.cs

@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using UnityEditor;
+using UnityEngine;
+
+namespace MyEditor
+{
+	public static class BTDesignerUtility
+	{
+		private static readonly string ImagePathName = "Assets/Editor/BehaviorTreeEditor/Pic/";
+
+		private static readonly Dictionary<string, Texture2D> mTextureDict = new Dictionary<string, Texture2D>();
+
+		public static Texture2D GetTexture(string imageName)
+		{
+			try
+			{
+				if (!mTextureDict.ContainsKey(imageName))
+				{
+					Texture2D tex = AssetDatabase.LoadAssetAtPath<Texture2D>(ImagePathName + imageName + ".png");
+					if (tex != null)
+					{
+						mTextureDict.Add(imageName, tex);
+					}
+				}
+				return mTextureDict[imageName];
+			}
+			catch (Exception e)
+			{
+				throw new Exception($"无法找到资源: {imageName}", e);
+			}
+		}
+
+		public static void DrawConnection(Vector2 src, Vector2 dst)
+		{
+			Vector3[] linePoints = { src, dst };
+			Handles.DrawAAPolyLine(GetTexture("default"), 3f, linePoints);
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/BTDesignerUtility.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: ce0da9cd0a3c87142b3f71a8f5816e2e
+timeCreated: 1445225656
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 168 - 0
Unity/Assets/Editor/BehaviorTreeEditor/BTEditorWindow.cs

@@ -0,0 +1,168 @@
+using System;
+using UnityEditor;
+using UnityEngine;
+
+namespace MyEditor
+{
+	public enum SubWinType
+	{
+		CreateNode,
+		ReplaceNode
+	}
+
+	public class MessageBoxArgs: EventArgs
+	{
+		public string msg;
+	}
+
+	public class BTEditorWindow: EditorWindow
+	{
+		private PropertyDesigner propDesigner;
+		private BehaviorTreeNodeClassPopup popUpMenu;
+
+		public GraphDesigner GraphDesigner { get; private set; }
+
+		public static BTEditorWindow Instance
+		{
+			get
+			{
+				return GetWindow<BTEditorWindow>(false, "行为树编辑器");
+			}
+		}
+
+		public static bool IsShowSubWin { get; private set; }
+
+		public static void ShowWindow()
+		{
+			BTEditorWindow target = GetWindow<BTEditorWindow>("行为树编辑器", false);
+			target.minSize = new Vector2(600f, 500f);
+		}
+
+		public void ShowSubWin(Vector2 pos, SubWinType subWinType)
+		{
+			IsShowSubWin = true;
+			popUpMenu.Show(windowRect, subWinType);
+			windowRect.position = pos;
+		}
+
+		public void CloseSubWin()
+		{
+			IsShowSubWin = false;
+		}
+
+		public static Rect windowRect = new Rect(400, 250, 400, 550); //子窗口的大小和位置
+
+		public void DrawSubWindow()
+		{
+			BeginWindows(); //标记开始区域所有弹出式窗口
+			windowRect = GUILayout.Window(1, windowRect, DoWindow, "行为树节点"); //创建内联窗口,参数分别为id,大小位置,创建子窗口的组件的函数,标题
+			EndWindows(); //标记结束
+		}
+
+		private void DoWindow(int unusedWindowID)
+		{
+			popUpMenu.DrawSearchList();
+			GUI.DragWindow(); //画出子窗口
+		}
+
+		public void Awake()
+		{
+			this.GraphDesigner = CreateInstance<GraphDesigner>();
+			this.propDesigner = CreateInstance<PropertyDesigner>();
+			popUpMenu = new BehaviorTreeNodeClassPopup
+			{
+				GraphDesigner = this.GraphDesigner
+			};
+		}
+
+		public void OnGUI()
+		{
+			HandleEvents();
+			this.propDesigner?.Draw();
+			this.GraphDesigner?.Draw(this.position);
+			if (IsShowSubWin)
+			{
+				DrawSubWindow();
+			}
+			this.Repaint();
+		}
+
+		public void HandleEvents()
+		{
+			Event e = Event.current;
+			switch (e.type)
+			{
+				case EventType.KeyUp:
+					if (e.keyCode == KeyCode.Escape || (e.keyCode == KeyCode.S && e.control))
+					{
+						BTEntity.Instance.SaveAll();
+					}
+					else if (e.keyCode == KeyCode.F4)
+					{
+						BTEntity.Instance.SaveAll();
+					}
+					break;
+				case EventType.MouseDown:
+					break;
+			}
+		}
+
+		public void OnDestroy()
+		{
+			BTEntity.Reset();
+		}
+
+		public void onUpdatePropList(params object[] list)
+		{
+			this.propDesigner.SetToolBar(0);
+		}
+
+		public void onShowMessage(params object[] list)
+		{
+			string msg = list[0].ToString();
+			this.ShowNotification(new GUIContent(msg));
+		}
+
+		public void OnSelectNode(params object[] list)
+		{
+			if (list.Length == 0)
+			{
+				Debug.LogError(" node list can not be null");
+				return;
+			}
+			this.GraphDesigner.onSelectNode(list);
+			this.propDesigner.onSelectNode(list);
+			//      mRightDesigner.onSelectNode(list);
+		}
+
+		public void onStartConnect(NodeDesigner nodeDesigner, State state)
+		{
+			this.GraphDesigner.onStartConnect(nodeDesigner, state);
+		}
+
+		public void onMouseInNode(BehaviorNodeData nodeData, NodeDesigner nodeDesigner)
+		{
+			this.GraphDesigner.onMouseInNode(nodeData, nodeDesigner);
+		}
+
+		public void onCreateNode(string name, Vector2 pos)
+		{
+			this.GraphDesigner.onCreateNode(name, pos);
+		}
+
+		public void onChangeNodeType(string name, Vector2 pos)
+		{
+			this.GraphDesigner.onChangeNodeType(name, pos);
+		}
+
+		public NodeDesigner onCreateTree()
+		{
+			return this.GraphDesigner.onCreateTree();
+		}
+
+		public void onDraggingRightDesigner(float deltaX)
+		{
+			//       mRightDesigner.onDraggingBorder(deltaX);
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/BTEditorWindow.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 720eaee451e99f7489b1943d53d9484a
+timeCreated: 1444988755
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 613 - 0
Unity/Assets/Editor/BehaviorTreeEditor/BTEntity.cs

@@ -0,0 +1,613 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using Model;
+using UnityEditor;
+using UnityEngine;
+using Component = UnityEngine.Component;
+using Object = UnityEngine.Object;
+
+namespace MyEditor
+{
+	public class BTEntity: Entity
+	{
+		private static BTEntity instance;
+
+		public const int NodeIdStartIndex = 100000;
+		private int AutoID = NodeIdStartIndex;
+
+		public GameObject CurTreeGO { get; set; }
+		public BehaviorTreeData CurTree { get; set; }
+
+		private Dictionary<string, NodeMeta> name2NodeProtoDict = new Dictionary<string, NodeMeta>(); //节点类型 name索引
+		public Dictionary<string, List<NodeMeta>> Classify2NodeProtoList { get; private set; } = new Dictionary<string, List<NodeMeta>>();
+
+		public string selectNodeName;
+		public string selectNodeType;
+
+		public BehaviorTreeConfig BehaviorTreeConfig
+		{
+			get
+			{
+				return CurTreeGO?.GetComponent<BehaviorTreeConfig>();
+			}
+		}
+
+		public static BTEntity Instance
+		{
+			get
+			{
+				if (instance != null)
+				{
+					return instance;
+				}
+
+				instance = new BTEntity();
+				instance.AddComponent<BTDebugComponent>();
+				return instance;
+			}
+		}
+
+		public static void Reset()
+		{
+			instance = null;
+		}
+
+		public NodeMeta GetNodeMeta(string nodeName)
+		{
+			NodeMeta nodeMeta = null;
+			this.name2NodeProtoDict.TryGetValue(nodeName, out nodeMeta);
+			return nodeMeta;
+		}
+
+		public List<NodeMeta> AllNodeProtoList
+		{
+			get
+			{
+				return name2NodeProtoDict.Values.ToList();
+			}
+		}
+
+		public void FilterClassify()
+		{
+			this.Classify2NodeProtoList = new Dictionary<string, List<NodeMeta>>();
+			foreach (NodeMeta nodeType in this.name2NodeProtoDict.Values)
+			{
+				if (nodeType.isDeprecated)
+				{
+					continue;
+				}
+				string classify = nodeType.classify;
+				if (classify == "")
+				{
+					classify = "未分类";
+				}
+				if (!this.Classify2NodeProtoList.ContainsKey(classify))
+				{
+					this.Classify2NodeProtoList.Add(classify, new List<NodeMeta>());
+				}
+				this.Classify2NodeProtoList[classify].Add(nodeType);
+			}
+		}
+
+		public int AutoNodeId()
+		{
+			return ++AutoID;
+		}
+
+		public void NewLoadData()
+		{
+			LoadNodeTypeProto();
+			NewLoadPrefabTree();
+			FilterClassify();
+		}
+
+		public void LoadNodeTypeProto()
+		{
+			this.name2NodeProtoDict = NodeMetaHelper.ExportToDict();
+		}
+
+		public void NewLoadPrefabTree()
+		{
+			BehaviorTreeConfig config = CurTreeGO.GetComponent<BehaviorTreeConfig>();
+			CurTree = BehaviorTreeConfigToTreeData(config);
+		}
+
+		public BehaviorTreeData BehaviorTreeConfigToTreeData(BehaviorTreeConfig config)
+		{
+			BehaviorTreeData tree = new BehaviorTreeData { Root = NodeConfigToNodeData(config.RootNodeConfig) };
+			return tree;
+		}
+
+		public void PrintTree(BehaviorNodeData nodeData)
+		{
+			Log.Info($"PrintTree  :  {nodeData.Id} {nodeData}");
+			foreach (BehaviorNodeData data in nodeData.children)
+			{
+				this.PrintTree(data);
+			}
+		}
+
+		public bool CheckSatisfyInput()
+		{
+			NodeProto rootNode = this.BehaviorNodeDataToNodeProto(CurTree.BehaviorNodeData);
+			return CheckNodeInput(rootNode);
+		}
+
+		public bool CheckNodeInput(NodeProto nodeProto)
+		{
+			List<NodeFieldDesc> list = NodeMetaHelper.GetNodeFieldInOutPutDescList(nodeProto.Name, typeof(NodeInputAttribute));
+			foreach (NodeFieldDesc desc in list)
+			{
+				List<string> canInputList = GetCanInPutEnvKeyList(this.NodeProtoToBehaviorNodeData(nodeProto), desc);
+				string value = nodeProto.Args.Get(desc.name)?.ToString();
+				List<string> resultList = canInputList.FindAll(str => str == value);
+				if (resultList.Count == 0)
+				{
+					Log.Error($"{nodeProto.Name}节点(id:{nodeProto.Id})的{value}输入值非法!");
+					return false;
+				}
+			}
+			foreach (NodeProto child in nodeProto.children)
+			{
+				if (!CheckNodeInput(child))
+				{
+					return false;
+				}
+			}
+			return true;
+		}
+
+		public void SaveAll()
+		{
+			if (!CheckHasTreeDesc())
+			{
+				return;
+			}
+			if (!CheckSatisfyInput())
+			{
+				return;
+			}
+			SavePrefabTree();
+			Log.Info("保存成功!");
+			BehaviorTreeTipsHelper.ShowMessage("保存成功!");
+		}
+
+		private void SavePrefabTree()
+		{
+			ResetTreeId();
+
+			BehaviorTreeConfig config = BehaviorTreeDataToConfig(CurTree);
+			RenameTree(config);
+			Object.DestroyImmediate(config.gameObject);
+		}
+
+		public void ResetTreeId()
+		{
+			AutoID = NodeIdStartIndex;
+			CurTree.Root.ResetId();
+		}
+		
+		public void RemoveUnusedArgs(NodeProto nodeProto)
+		{
+			NodeMeta proto = BTEntity.Instance.GetNodeMeta(nodeProto.Name);
+			List<string> unUsedList = new List<string>();
+			foreach (KeyValuePair<string, object> item in nodeProto.Args.Dict())
+			{
+				if (!proto.new_args_desc.Exists(a => (a.name == item.Key)))
+				{
+					unUsedList.Add(item.Key);
+				}
+			}
+			foreach (string item in unUsedList)
+			{
+				nodeProto.Args.Remove(item);
+			}
+			for (int i = 0; i < nodeProto.children.Count; i++)
+			{
+				RemoveUnusedArgs(nodeProto.children[i]);
+			}
+		}
+
+		private bool CheckHasTreeDesc()
+		{
+			if (string.IsNullOrEmpty(CurTree.Root.Desc))
+			{
+				Log.Error("行为树描述不可以不填!!!!!!");
+				return false;
+			}
+			return true;
+		}
+
+		public void RenameTree(BehaviorTreeConfig config)
+		{
+			string newName = $"{config.RootNodeConfig.describe}";
+			if (!config.RootNodeConfig.describe.StartsWith("BT_"))
+			{
+				newName = $"BT_{config.RootNodeConfig.describe}";
+			}
+			config.gameObject.name = newName;
+			CurTreeGO = PrefabUtility.ReplacePrefab(config.gameObject, CurTreeGO, ReplacePrefabOptions.ReplaceNameBased);
+			string prefabPath = AssetDatabase.GetAssetPath(CurTreeGO);
+			string result = AssetDatabase.RenameAsset(prefabPath, newName);
+			if (result.Contains("Invalid file name"))
+			{
+				Log.Error(result);
+			}
+			EditorUtility.SetDirty(config.gameObject);
+		}
+
+		public BehaviorTreeConfig BehaviorTreeDataToConfig(BehaviorTreeData tree)
+		{
+			GameObject curTreeGo = Object.Instantiate(CurTreeGO);
+			BehaviorTreeConfig config = curTreeGo.GetComponent<BehaviorTreeConfig>();
+			if (config == null)
+			{
+				config = curTreeGo.AddComponent<BehaviorTreeConfig>();
+			}
+			foreach (Transform child in config.gameObject.transform)
+			{
+				Object.DestroyImmediate(child.gameObject);
+			}
+			try
+			{
+				config.RootNodeConfig = this.BehaviorNodeDataToNodeConfig(tree.Root);
+			}
+			catch (Exception e)
+			{
+				Log.Error($"tree name : {tree.BehaviorNodeData.Name} {e}");
+			}
+
+			config.RootNodeConfig.gameObject.transform.parent = config.gameObject.transform;
+			return config;
+		}
+
+		public BehaviorNodeData NodeConfigToNodeData(BehaviorNodeConfig nodeProto)
+		{
+			BehaviorNodeData nodeData = new BehaviorNodeData();
+			nodeData.Id = nodeProto.id;
+			nodeData.Name = nodeProto.name;
+			nodeData.Desc = nodeProto.describe;
+			nodeData.Args = nodeProto.GetArgsDict();
+			nodeData.children = new List<BehaviorNodeData>();
+			//             foreach (var item in nodeData.Args)
+			//             {
+			//                 Log.Info($"key :{item.Key} value :{item.Value}");
+			//             }
+			foreach (Transform child in nodeProto.gameObject.transform)
+			{
+				BehaviorNodeConfig nodeConfig = child.gameObject.GetComponent<BehaviorNodeConfig>();
+				BehaviorNodeData childData = NodeConfigToNodeData(nodeConfig);
+				nodeData.children.Add(childData);
+			}
+			return nodeData;
+		}
+
+		public BehaviorNodeConfig BehaviorNodeDataToNodeConfig(BehaviorNodeData nodeData)
+		{
+			GameObject go = new GameObject();
+			BehaviorNodeConfig nodeConfig = go.AddComponent<BehaviorNodeConfig>();
+			nodeConfig.id = nodeData.Id;
+			nodeConfig.name = nodeData.Name;
+			go.name = nodeData.Name;
+			nodeConfig.describe = nodeData.Desc;
+			List<string> unUseList = new List<string>();
+			foreach (KeyValuePair<string, object> args in nodeData.Args.Dict())
+			{
+				if (!NodeMetaHelper.NodeHasField(nodeData.Name, args.Key))
+				{
+					unUseList.Add(args.Key);
+					continue;
+				}
+				Type originType = NodeMetaHelper.GetFieldType(nodeData.Name, args.Key);
+				try
+				{
+					string fieldName = args.Key;
+					object fieldValue = args.Value;
+					Type type = BTTypeManager.GetBTType(originType);
+					Component comp = go.AddComponent(type);
+					FieldInfo fieldNameInfo = type.GetField("fieldName");
+					fieldNameInfo.SetValue(comp, fieldName);
+					FieldInfo fieldValueinfo = type.GetField("fieldValue");
+					if (TypeHelper.IsEnumType(originType))
+					{
+						fieldValue = fieldValue.ToString();
+					}
+					fieldValueinfo.SetValue(comp, fieldValue);
+				}
+				catch (Exception e)
+				{
+					throw new Exception($"transform failed,nodeName:{nodeData.Name}  fieldName:{args.Key} fieldType:{originType}", e);
+				}
+			}
+			foreach (string key in unUseList)
+			{
+				nodeData.Args.Remove(key);
+			}
+			foreach (BehaviorNodeData child in nodeData.children)
+			{
+				BehaviorNodeConfig childConfig = this.BehaviorNodeDataToNodeConfig(child);
+				childConfig.gameObject.transform.parent = nodeConfig.gameObject.transform;
+			}
+			return nodeConfig;
+		}
+
+		public BehaviorNodeData NodeProtoToBehaviorNodeData(NodeProto nodeProto)
+		{
+			BehaviorNodeData nodeData = new BehaviorNodeData
+			{
+				Id = nodeProto.Id,
+				Name = nodeProto.Name,
+				Desc = nodeProto.Desc,
+				Args = nodeProto.Args,
+				children = new List<BehaviorNodeData>()
+			};
+			foreach (NodeProto child in nodeProto.children)
+			{
+				nodeData.children.Add(this.NodeProtoToBehaviorNodeData(child));
+			}
+			return nodeData;
+		}
+
+		public NodeProto BehaviorNodeDataToNodeProto(BehaviorNodeData nodeData)
+		{
+			NodeProto nodeProto = new NodeProto
+			{
+				Id = nodeData.Id,
+				Name = nodeData.Name,
+				Desc = nodeData.Desc,
+				Args = nodeData.Args,
+				children = new List<NodeProto>()
+			};
+			foreach (BehaviorNodeData child in nodeData.children)
+			{
+				nodeProto.children.Add(this.BehaviorNodeDataToNodeProto(child));
+			}
+			return nodeProto;
+		}
+
+		//private List<NodeFieldDesc> GetFieldDescList(NodeProto nodeProto, Type type)
+		//{
+		//	List<NodeFieldDesc> list = NodeMetaHelper.GetNodeFieldInOutPutDescList(nodeProto.name, type);
+		//	foreach (NodeProto childProto in nodeProto.children)
+		//	{
+		//		list.AddRange(GetFieldDescList(childProto, type));
+		//	}
+		//	return list;
+		//}
+
+		public BehaviorNodeData CreateNode(int treeId, string nodeName)
+		{
+			if (!this.name2NodeProtoDict.ContainsKey(nodeName))
+			{
+				Debug.LogError($"节点类型:{nodeName}不存在");
+				return null;
+			}
+			BehaviorNodeData node = new BehaviorNodeData(nodeName);
+			node.Id = AutoNodeId();
+			node.Name = nodeName;
+			return node;
+		}
+
+		public BehaviorNodeData CopyNode(BehaviorNodeData node)
+		{
+			BehaviorNodeData copyNode = new BehaviorNodeData
+			{
+				Name = node.Name,
+				Desc = node.Desc,
+				Pos = node.Pos,
+				Args = node.Args.Clone()
+			};
+			List<BehaviorNodeData> list = new List<BehaviorNodeData>();
+			foreach (BehaviorNodeData item in node.children)
+			{
+				list.Add(item);
+			}
+			foreach (BehaviorNodeData child in list)
+			{
+				copyNode.AddChild(CopyNode(child));
+			}
+			copyNode.ResetId();
+			return copyNode;
+		}
+
+		public void OpenBehaviorEditor(GameObject go)
+		{
+			if (go == null)
+			{
+				return;
+			}
+			selectNodeName = "";
+			CurTreeGO = go;
+			NewLoadData();
+			BTEditorWindow.ShowWindow();
+			Game.Scene.GetComponent<EventComponent>().Run(EventIdType.BehaviorTreeOpenEditor);
+		}
+
+		public string[] GetCanInPutEnvKeyArray(BehaviorNodeData nodeData, NodeFieldDesc desc)
+		{
+			List<string> list1 = new List<string>();
+			list1.AddRange(Instance.GetNodeOutPutEnvKeyList(nodeData, desc));
+			list1.Add(BTEnvKey.None);
+			HashSet<string> hashSet = new HashSet<string>();
+			foreach (string item in list1)
+			{
+				hashSet.Add(item);
+			}
+
+			string[] strArr = new string[hashSet.Count];
+			int i = 0;
+			foreach (string str in hashSet)
+			{
+				strArr[i++] = str;
+			}
+			return strArr;
+		}
+
+		public List<string> GetCanInPutEnvKeyList(BehaviorNodeData nodeData, NodeFieldDesc desc)
+		{
+			List<string> list1 = Instance.GetNodeOutPutEnvKeyList(nodeData, desc);
+			HashSet<string> hashSet = new HashSet<string>();
+			foreach (string item in list1)
+			{
+				hashSet.Add(item);
+			}
+			List<string> resultList = new List<string>();
+			foreach (string item in hashSet)
+			{
+				resultList.Add(item);
+			}
+			return resultList;
+		}
+
+		public List<string> GetNodeOutPutEnvKeyList(BehaviorNodeData nodeData, NodeFieldDesc desc = null)
+		{
+			NodeProto rootNode = this.BehaviorNodeDataToNodeProto(CurTree.Root);
+			NodeProto inputNode = this.BehaviorNodeDataToNodeProto(nodeData);
+			List<NodeFieldDesc> descList = _GetNodeOutPutEnvKeyList(rootNode, inputNode, desc);
+			List<string> list = new List<string>();
+			foreach (NodeFieldDesc item in descList)
+			{
+				string str = item.value?.ToString() ?? "";
+				list.Add(str);
+			}
+			return list;
+		}
+
+		private static List<NodeFieldDesc> _GetNodeOutPutEnvKeyList(NodeProto nodeProto, NodeProto inputNode, NodeFieldDesc desc = null)
+		{
+			if (nodeProto.Id >= inputNode.Id)
+			{
+				return new List<NodeFieldDesc>();
+			}
+			List<NodeFieldDesc> list = new List<NodeFieldDesc>();
+
+			if (desc == null)
+			{
+				list = NodeMetaHelper.GetNodeFieldInOutPutDescList(nodeProto.Name, typeof(NodeOutputAttribute));
+			}
+			else
+			{
+				list = NodeMetaHelper.GetNodeFieldInOutPutFilterDescList(nodeProto.Name, typeof(NodeOutputAttribute), desc.envKeyType);
+			}
+			for (int i = 0; i < list.Count; i++)
+			{
+				object value = nodeProto.Args.Get(list[i].name);
+				list[i].value = value;
+			}
+
+			foreach (NodeProto childProto in nodeProto.children)
+			{
+				list.AddRange(_GetNodeOutPutEnvKeyList(childProto, inputNode, desc));
+			}
+			return list;
+		}
+
+		public List<string> GetSelectNodeInputValueList(NodeProto nodeProto)
+		{
+			List<string> resultList = new List<string>();
+			List<NodeFieldDesc> list = NodeMetaHelper.GetNodeFieldInOutPutDescList(nodeProto.Name, typeof(NodeInputAttribute));
+
+			foreach (NodeFieldDesc desc in list)
+			{
+				string value = nodeProto.Args.Get(desc.name)?.ToString();
+				resultList.Add(value);
+			}
+			return resultList;
+		}
+		
+		private List<string> inputValueList;
+
+		public void SelectNode(BehaviorNodeData node)
+		{
+			NodeProto nodeProto = this.BehaviorNodeDataToNodeProto(node);
+			inputValueList = GetSelectNodeInputValueList(nodeProto);
+		}
+
+		public bool IsHighLight(BehaviorNodeData node)
+		{
+			NodeProto nodeProto = this.BehaviorNodeDataToNodeProto(node);
+			List<NodeFieldDesc> list = NodeMetaHelper.GetNodeFieldInOutPutDescList(nodeProto.Name, typeof(NodeOutputAttribute));
+			foreach (NodeFieldDesc desc in list)
+			{
+				if (!nodeProto.Args.ContainsKey(desc.name))
+				{
+					continue;
+				}
+				string value = nodeProto.Args.Get(desc.name)?.ToString();
+				List<string> resultList = inputValueList.FindAll(str => { return str == value; });
+				if (resultList.Count > 0)
+				{
+					return true;
+				}
+			}
+			return false;
+		}
+
+		public void SetDebugState(List<long> pathList)
+		{
+			foreach (long nodeId in pathList)
+			{
+				Instance.SetDebugState((int) nodeId);
+			}
+		}
+
+		private void SetDebugState(int nodeId)
+		{
+			if (this.BehaviorTreeConfig != null)
+			{
+				BehaviorNodeData nodeData = GetNodeData(CurTree.Root, nodeId);
+				if (nodeData != null)
+				{
+					nodeData.NodeDeubgState = DebugState.True;
+				}
+			}
+		}
+
+		public void ClearDebugState()
+		{
+			_ClearDebugState(CurTree.Root);
+		}
+
+		private static void _ClearDebugState(BehaviorNodeData nodeData)
+		{
+			nodeData.NodeDeubgState = DebugState.Normal;
+			foreach (BehaviorNodeData child in nodeData.children)
+			{
+				_ClearDebugState(child);
+			}
+		}
+
+		public BehaviorNodeData GetNodeData(BehaviorNodeData nodeData, int nodeId)
+		{
+			BehaviorNodeData result = null;
+			if (nodeData.Id == nodeId)
+			{
+				return nodeData;
+			}
+			foreach (BehaviorNodeData child in nodeData.children)
+			{
+				result = GetNodeData(child, nodeId);
+				if (result != null)
+				{
+					break;
+				}
+			}
+			return result;
+		}
+
+		public BehaviorNodeData GetNode(BehaviorNodeData nodeData, int nodeId)
+		{
+			if (nodeData.Id == nodeId)
+			{
+				return nodeData;
+			}
+			foreach (BehaviorNodeData data in nodeData.children)
+			{
+				return GetNode(data, nodeId);
+			}
+			return null;
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/BTEntity.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 51f78e8a455fac3408d55a96863e7037
+timeCreated: 1445240657
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 67 - 0
Unity/Assets/Editor/BehaviorTreeEditor/BehaviorNodeConfigExtension.cs

@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using MyEditor;
+using UnityEngine;
+
+namespace Model
+{
+	public static class BehaviorNodeConfigExtension
+	{
+		public static BehaviorNodeConfig ProtoToConfig(NodeProto nodeData)
+		{
+			GameObject go = new GameObject();
+			BehaviorNodeConfig nodeConfig = go.AddComponent<BehaviorNodeConfig>();
+			nodeConfig.id = nodeData.Id;
+			nodeConfig.name = nodeData.Name;
+			go.name = nodeData.Name;
+			nodeConfig.describe = nodeData.Desc;
+			foreach (KeyValuePair<string, object> args in nodeData.Args.Dict())
+			{
+				Type originType = NodeMetaHelper.GetFieldType(nodeData.Name, args.Key);
+				try
+				{
+					string fieldName = args.Key;
+					object fieldValue = args.Value;
+					Type type = BTTypeManager.GetBTType(originType);
+					UnityEngine.Component comp = go.AddComponent(type);
+					FieldInfo fieldNameInfo = type.GetField("fieldName");
+					fieldNameInfo.SetValue(comp, fieldName);
+					FieldInfo fieldValueinfo = type.GetField("fieldValue");
+					if (TypeHelper.IsEnumType(originType))
+					{
+						fieldValue = fieldValue.ToString();
+					}
+					fieldValueinfo.SetValue(comp, fieldValue);
+				}
+				catch (Exception e)
+				{
+					throw new Exception($"transform failed,nodeName:{nodeData.Name}  fieldName:{args.Key} fieldType:{originType} {e}");
+				}
+			}
+			foreach (NodeProto child in nodeData.children)
+			{
+				BehaviorNodeConfig childConfig = ProtoToConfig(child);
+				childConfig.gameObject.transform.parent = nodeConfig.gameObject.transform;
+			}
+			return nodeConfig;
+		}
+
+		public static NodeProto ConfigToNode(BehaviorNodeConfig nodeProto)
+		{
+			NodeProto nodeData = new NodeProto();
+			nodeData.Id = nodeProto.id;
+			nodeData.Name = nodeProto.name;
+			nodeData.Desc = nodeProto.describe;
+			nodeData.Args = nodeProto.GetArgsDict();
+			nodeData.children = new List<NodeProto>();
+			foreach (Transform child in nodeProto.gameObject.transform)
+			{
+				BehaviorNodeConfig nodeConfig = child.gameObject.GetComponent<BehaviorNodeConfig>();
+				NodeProto childData = ConfigToNode(nodeConfig);
+				nodeData.children.Add(childData);
+			}
+			return nodeData;
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/BehaviorNodeConfigExtension.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 49cadc7f01272b6478e89ac498c2f973
+timeCreated: 1478145751
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 118 - 0
Unity/Assets/Editor/BehaviorTreeEditor/BehaviorNodeData.cs

@@ -0,0 +1,118 @@
+using System.Collections.Generic;
+using Model;
+using UnityEngine;
+
+namespace MyEditor
+{
+	public enum DebugState
+	{
+		Disable,
+		True,
+		False,
+		Error,
+		Normal
+	}
+
+	public class BehaviorNodeData
+	{
+		public int Id;
+
+		public string Name;
+
+		public string Desc = "";
+
+		public List<BehaviorNodeData> children = new List<BehaviorNodeData>();
+
+		public BehaviorTreeArgsDict Args = new BehaviorTreeArgsDict();
+
+		/// <summary>
+		///  
+		/// </summary>
+		public string Error = "";
+
+		public NodeDesigner NodeDesigner { get; set; }
+
+		public Vector2 Pos;
+		public DebugState NodeDeubgState { get; set; }
+		public string time;
+
+		public NodeMeta Proto { get; set; }
+
+		public List<BehaviorNodeData> Children
+		{
+			get
+			{
+				return children;
+			}
+		}
+
+		public BehaviorNodeData Parent { get; set; }
+
+		public string Classify { get; set; } = "";
+
+		public BehaviorNodeData(string proto_name)
+		{
+			this.Name = proto_name;
+			this.Proto = BTEntity.Instance.GetNodeMeta(proto_name);
+			if (this.Proto == null)
+			{
+				this.Proto = BTEntity.Instance.GetNodeMeta("Unknow");
+				return;
+			}
+			this.Classify = this.Proto.classify;
+
+			foreach (NodeFieldDesc args_desc in this.Proto.new_args_desc)
+			{
+				this.Args.SetKeyValueComp(args_desc.name, args_desc.value);
+			}
+
+			foreach (BehaviorNodeData child in children)
+			{
+				AddChild(child);
+			}
+		}
+
+		public BehaviorNodeData()
+		{
+		}
+
+		//默认添加到末尾
+		public void AddChild(BehaviorNodeData node, int index = -1)
+		{
+			index = index == -1? this.Children.Count : index;
+			children.Insert(index, node);
+			node.Parent = this;
+		}
+
+		public BehaviorNodeData RemoveChild(BehaviorNodeData node)
+		{
+			node.Parent = null;
+			children.Remove(node);
+			return node;
+		}
+
+		public bool IsLeaf()
+		{
+			return children.Count == 0;
+		}
+
+		public bool IsRoot()
+		{
+			return Parent == null;
+		}
+
+		public bool CanAddChild()
+		{
+			return children.Count < Proto.child_limit;
+		}
+
+		public void ResetId()
+		{
+			this.Id = BTEntity.Instance.AutoNodeId();
+			foreach (BehaviorNodeData child in children)
+			{
+				child.ResetId();
+			}
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/BehaviorNodeData.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: c08bbb6fa338299459fb5f68293508e6
+timeCreated: 1445412259
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 22 - 0
Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeConfigEditor.cs

@@ -0,0 +1,22 @@
+using Model;
+using UnityEditor;
+using UnityEngine;
+
+namespace MyEditor
+{
+	[CustomEditor(typeof(BehaviorTreeConfig))]
+	public class BehaviorTreeConfigEditor: Editor
+	{
+		public override void OnInspectorGUI()
+		{
+			base.OnInspectorGUI();
+			BehaviorTreeConfig config = target as BehaviorTreeConfig;
+
+			if (GUILayout.Button("打开行为树"))
+			{
+				BTEntity.Instance.OpenBehaviorEditor(config.gameObject);
+			}
+			EditorUtility.SetDirty(config);
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeConfigEditor.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 8da8c0787633f634f8bfe3d81cba5a86
+timeCreated: 1486456203
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 56 - 0
Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeConfigExtension.cs

@@ -0,0 +1,56 @@
+using System;
+using System.Reflection;
+using MyEditor;
+using UnityEngine;
+
+namespace Model
+{
+	public static class BehaviorTreeConfigExtension
+	{
+		public static BehaviorNodeConfig AddRootNode(this BehaviorTreeConfig treeConfig, string rootName)
+		{
+			BehaviorNodeConfig go = treeConfig.CreateNodeConfig(rootName);
+			treeConfig.RootNodeConfig = go.GetComponent<BehaviorNodeConfig>();
+			treeConfig.RootNodeConfig.id = BTEntity.NodeIdStartIndex;
+			go.gameObject.name = rootName;
+			return go;
+		}
+
+		public static BehaviorNodeConfig AddChild(this BehaviorTreeConfig treeConfig, BehaviorNodeConfig parent, string name)
+		{
+			BehaviorNodeConfig child = treeConfig.CreateNodeConfig(name);
+			AddChild(treeConfig, parent, child);
+			return child;
+		}
+
+		public static BehaviorNodeConfig AddChild(this BehaviorTreeConfig treeConfig, BehaviorNodeConfig parent, BehaviorNodeConfig child)
+		{
+			child.transform.parent = parent.transform;
+			child.transform.SetAsLastSibling();
+			child.GetComponent<BehaviorNodeConfig>().id = treeConfig.RootNodeId + treeConfig.AutoId;
+			return child.GetComponent<BehaviorNodeConfig>();
+		}
+
+		private static BehaviorNodeConfig CreateNodeConfig(this BehaviorTreeConfig treeConfig, string name)
+		{
+			NodeMeta proto = BTEntity.Instance.GetNodeMeta(name);
+			GameObject go = new GameObject();
+			go.name = name;
+			go.transform.parent = treeConfig.gameObject.transform;
+			BehaviorNodeConfig node = go.AddComponent<BehaviorNodeConfig>();
+			node.name = name;
+			node.describe = proto.describe;
+
+			foreach (NodeFieldDesc args in proto.new_args_desc)
+			{
+				Type type = BTTypeManager.GetBTType(args.type);
+				UnityEngine.Component comp = go.AddComponent(type);
+				FieldInfo info = type.GetField("fieldName");
+				info.SetValue(comp, args.name);
+				FieldInfo info1 = type.GetField("fieldValue");
+				info1.SetValue(comp, args.value);
+			}
+			return node;
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeConfigExtension.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 6fdeb0fb0ced28142bb395d960a007ac
+timeCreated: 1478156746
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 42 - 0
Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeData.cs

@@ -0,0 +1,42 @@
+using System;
+using Model;
+using MongoDB.Bson.Serialization.Attributes;
+
+namespace MyEditor
+{
+	[BsonIgnoreExtraElements]
+	[Serializable]
+	public class BehaviorTreeData
+	{
+		public long Id;
+
+		[BsonElement, BsonIgnoreIfNull]
+		public BehaviorNodeData BehaviorNodeData;
+
+		[BsonElement]
+		public string classify = "";
+
+		public BehaviorTreeData()
+		{
+			this.Id = IdGenerater.GenerateId();
+		}
+
+		public BehaviorTreeData(long id)
+		{
+			this.Id = id;
+		}
+
+		[BsonIgnore]
+		public BehaviorNodeData Root
+		{
+			get
+			{
+				return this.BehaviorNodeData;
+			}
+			set
+			{
+				this.BehaviorNodeData = value;
+			}
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeData.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: d54aa5d9bac653246af829f4907826cf
+timeCreated: 1447145739
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 22 - 0
Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeMenu.cs

@@ -0,0 +1,22 @@
+using System.IO;
+using UnityEditor;
+using UnityEngine;
+
+namespace MyEditor
+{
+	public class AlterBundleNameWindow: EditorWindow
+	{
+		[MenuItem("Assets/Create/创建行为树")]
+		private static void CreateBehaviorTree()
+		{
+			string folderPath = AssetDatabase.GetAssetPath(Selection.activeObject);
+			if ((File.GetAttributes(folderPath) & FileAttributes.Directory) != FileAttributes.Directory)
+			{
+				GUILayout.Label("请选择一个文件夹");
+				return;
+			}
+
+			BehaviorTreeOperateUtility.CreateNewTree($"{folderPath}", "Root");
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeMenu.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 7ba79f825cb73b744901c844579efd3e
+timeCreated: 1486455928
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 159 - 0
Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeNodeClassPopup.cs

@@ -0,0 +1,159 @@
+using System;
+using System.Collections.Generic;
+using Model;
+using UnityEditor;
+using UnityEngine;
+
+namespace MyEditor
+{
+	public class BehaviorTreeNodeClassPopup
+	{
+		private string mSearchNode = "";
+		private Vector2 mTreeScrollPos = Vector2.zero;
+		private const float mWidth = 400f;
+
+		public GraphDesigner GraphDesigner;
+		private SubWinType mSubWinType;
+		public Rect windowRect; //子窗口的大小和位置
+		private string[] mEnumNodeTypeArr;
+		private Rect toolbarRect = new Rect(0f, 0f, 0, 0);
+		private int mEnumNodeTypeSelection;
+
+		public string DrawSearchList()
+		{
+			List<string> targetList = new List<string>();
+			if (mSubWinType == SubWinType.CreateNode)
+			{
+				targetList = GraphDesigner.GetCanCreateList();
+			}
+			else if (mSubWinType == SubWinType.ReplaceNode)
+			{
+				targetList = GraphDesigner.GetCanRepalceList();
+			}
+
+			List<string> nodeNameList = Filter(targetList, mSearchNode);
+
+			GUILayout.BeginHorizontal();
+			GUI.SetNextControlName("Search");
+			this.mSearchNode = GUILayout.TextField(this.mSearchNode, GUI.skin.FindStyle("ToolbarSeachTextField"));
+			GUI.FocusControl("Search");
+			GUILayout.EndHorizontal();
+			//
+			toolbarRect = new Rect(0f, 15f + 20, mWidth, 25f);
+			GUILayout.BeginArea(toolbarRect, EditorStyles.toolbar);
+			GUILayout.BeginHorizontal();
+
+			GUILayout.Label("Filter");
+			Array strArr = Enum.GetValues(typeof(NodeClassifyType));
+			List<string> strList = new List<string>();
+			strList.Add("All");
+			foreach (object str in strArr)
+			{
+				strList.Add(str.ToString());
+			}
+			mEnumNodeTypeArr = strList.ToArray();
+			mEnumNodeTypeSelection = EditorGUILayout.Popup(mEnumNodeTypeSelection, mEnumNodeTypeArr);
+			if (GUILayout.Button("Clear"))
+			{
+				ClearNodes();
+			}
+			GUILayout.EndHorizontal();
+			GUILayout.EndArea();
+			//
+
+			GUILayout.BeginArea(new Rect(0, 0, windowRect.width, windowRect.height));
+			float topSpace = 60;
+			this.mTreeScrollPos = GUI.BeginScrollView(new Rect(0f, topSpace, windowRect.width, windowRect.height - topSpace), this.mTreeScrollPos,
+			                                          new Rect(0f, 0f, windowRect.width - 20f, nodeNameList.Count * 19), false, true);
+
+			foreach (string name in nodeNameList)
+			{
+				NodeMeta proto = BTEntity.Instance.GetNodeMeta(name);
+				if (GUILayout.Button(name + $"({proto.describe})", GetButtonStyle()))
+				{
+					if (SubWinType.CreateNode == mSubWinType)
+					{
+						GraphDesigner.onCreateNode(name, Vector2.zero);
+					}
+					else if (SubWinType.ReplaceNode == mSubWinType)
+					{
+						GraphDesigner.onChangeNodeType(name, Vector2.zero);
+					}
+					BTEditorWindow.Instance.CloseSubWin();
+				}
+			}
+
+			GUI.EndScrollView();
+			GUILayout.EndArea();
+
+			return "";
+		}
+
+		private void ClearNodes()
+		{
+			mEnumNodeTypeSelection = 0;
+			mSearchNode = "";
+		}
+
+		public List<string> Filter(List<string> list, string text)
+		{
+			List<string> result1 = new List<string>();
+			string selectType;
+			if (mEnumNodeTypeSelection == 0)
+			{
+				selectType = "All";
+				result1 = list;
+			}
+			else
+			{
+				selectType = Enum.GetName(typeof(NodeClassifyType), mEnumNodeTypeSelection - 1);
+				foreach (string name in list)
+				{
+					NodeMeta proto = BTEntity.Instance.GetNodeMeta(name);
+					if (selectType == proto.classify)
+					{
+						result1.Add(name);
+					}
+				}
+			}
+
+			if (string.IsNullOrEmpty(text))
+			{
+				return result1;
+			}
+
+			List<string> result2 = new List<string>();
+			foreach (string name in result1)
+			{
+				NodeMeta proto = BTEntity.Instance.GetNodeMeta(name);
+				if (name.ToUpper().Contains(text.ToUpper()) || proto.describe.ToUpper().Contains(text.ToUpper()))
+				{
+					result2.Add(name);
+				}
+			}
+			return result2;
+		}
+		
+		public GUIStyle GetButtonStyle()
+		{
+			GUIStyle style = new GUIStyle();
+			style.fontSize = 15;
+			style.alignment = TextAnchor.MiddleLeft;
+			GUIStyleState onHoverStyleState = new GUIStyleState();
+			//onHoverStyleState.textColor = textHighLightColor;
+			onHoverStyleState.background = BTDesignerUtility.GetTexture("blue");
+			style.hover = onHoverStyleState;
+
+			GUIStyleState onNormalStyleState = new GUIStyleState();
+			//onNormalStyleState.textColor = textColor;
+			style.normal = onNormalStyleState;
+			return style;
+		}
+
+		public void Show(Rect rect, SubWinType subWinType)
+		{
+			windowRect = rect;
+			mSubWinType = subWinType;
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeNodeClassPopup.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 6a1eb8d5c2d0bee48a4c3d8b7c26ae4e
+timeCreated: 1473220994
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 157 - 0
Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeOperateUtility.cs

@@ -0,0 +1,157 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using Model;
+using UnityEditor;
+using UnityEngine;
+using Object = UnityEngine.Object;
+
+namespace MyEditor
+{
+	public class BehaviourTreeNodeProxy<T> where T : Node
+	{
+		public T Node;
+		public NodeProto Proto;
+
+		public BehaviourTreeNodeProxy(NodeProto p)
+		{
+			Node = (T) Activator.CreateInstance(typeof(T), p);
+			Proto = p;
+			UpdateData();
+		}
+
+		public void SetDescribe(string desc)
+		{
+			Proto.Desc = desc;
+		}
+
+		public void Apply()
+		{
+			FieldInfo[] mems = Node.GetType().GetFields();
+			foreach (FieldInfo mem in mems)
+			{
+				Proto.Args.SetKeyValueComp(mem.Name, mem.GetValue(Node));
+			}
+		}
+
+		public NodeProto GetNodeProtoCopy()
+		{
+			return BehaviorTreeOperateUtility.NodeProtoParamClone(Proto);
+		}
+
+		public void UpdateData()
+		{
+			foreach (KeyValuePair<string, object> argsItem in Proto.Args.Dict())
+			{
+				FieldInfo fieldInfo = typeof(T).GetField(argsItem.Key, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
+				fieldInfo.SetValue(Node, argsItem.Value);
+			}
+		}
+	}
+
+	public static class BehaviorTreeOperateUtility
+	{
+		/// <summary>
+		/// 克隆Node Proto的参数队列
+		/// </summary>
+		/// <param name="p"></param>
+		/// <returns></returns>
+		public static NodeProto NodeProtoParamClone(NodeProto p)
+		{
+			NodeProto newP = new NodeProto(p.Args.Clone());
+			return newP;
+		}
+
+		public static GameObject CreateTreeWithType<T>(string path, string desc = "默认行为树")
+		{
+			desc = desc.Replace("BT_", "");
+			return CreateTree(path, typeof(T).Name, desc);
+		}
+
+		public static GameObject CreateTree(string path, string rootNodeName, string desc = "默认行为树")
+		{
+			GameObject prefab = null;
+			try
+			{
+				GameObject go = new GameObject();
+				go.name = desc;
+				prefab = PrefabUtility.CreatePrefab($"{path}/BT_{desc}.prefab", go, ReplacePrefabOptions.ReplaceNameBased);
+				BehaviorTreeConfig config = prefab.AddComponent<BehaviorTreeConfig>();
+				config.AddRootNode(rootNodeName);
+				EditorUtility.SetDirty(config);
+				EditorUtility.SetDirty(prefab);
+				Object.DestroyImmediate(go);
+			}
+			catch (Exception ex)
+			{
+				Log.Error($"创建行为树失败|{ex}");
+			}
+			return prefab;
+		}
+
+		public static GameObject CreateNewTree(string path, string rootNodeName, string desc = "默认行为树")
+		{
+			GameObject prefab = null;
+			try
+			{
+				GameObject go = new GameObject();
+				BehaviorTreeConfig newConfig = go.AddComponent<BehaviorTreeConfig>();
+				newConfig.AddRootNode(rootNodeName);
+
+				prefab = PrefabUtility.CreatePrefab($"{path}/BT_{desc}.prefab", go, ReplacePrefabOptions.ReplaceNameBased);
+				EditorUtility.SetDirty(newConfig);
+				EditorUtility.SetDirty(prefab);
+				Object.DestroyImmediate(go);
+			}
+			catch (Exception ex)
+			{
+				Log.Error($"创建行为树失败|{ex}");
+			}
+			return prefab;
+		}
+		
+		public static BehaviourTreeNodeProxy<T> AddNodeToLast<T>(BehaviorTreeConfig tree) where T : Node
+		{
+			BehaviorNodeConfig parent = tree.RootNodeConfig;
+			string name = typeof(T).Name;
+			BehaviorNodeConfig p = tree.AddChild(parent, name);
+			BehaviourTreeNodeProxy<T> proxy = new BehaviourTreeNodeProxy<T>(p.ToNodeProto());
+			return proxy;
+		}
+
+		public static BehaviourTreeNodeProxy<T> CreateNode<T>() where T : Node
+		{
+			NodeProto p = new NodeProto();
+			p.Name = typeof(T).Name;
+			BehaviourTreeNodeProxy<T> proxy = new BehaviourTreeNodeProxy<T>(p);
+			return proxy;
+		}
+
+		/// <summary>
+		/// 从父节点获取某个指定名字的子节点
+		/// </summary>
+		/// <param name="list"></param>
+		/// <param name="name"></param>
+		/// <param name="p"></param>
+		/// <returns></returns>
+		public static bool TryGetActionChild(List<NodeProto> list, string name, out NodeProto p)
+		{
+			foreach (NodeProto proto in list)
+			{
+				if (proto.Desc == name)
+				{
+					p = proto;
+					return true;
+				}
+			}
+			p = null;
+			return false;
+		}
+
+		public static BTEditorTree Open(GameObject go)
+		{
+			BehaviorTreeConfig config = go.GetComponent<BehaviorTreeConfig>();
+			return new BTEditorTree(config);
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeOperateUtility.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: ad28444131f02094f88419500ac48038
+timeCreated: 1486455928
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 13 - 0
Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeTipsHelper.cs

@@ -0,0 +1,13 @@
+using UnityEngine;
+
+namespace MyEditor
+{
+	public static class BehaviorTreeTipsHelper
+	{
+		public static void ShowMessage(params object[] list)
+		{
+			string msg = list[0].ToString();
+			BTEditorWindow.Instance.ShowNotification(new GUIContent(msg));
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/BehaviorTreeTipsHelper.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 2860b7daa4ea5aa4196cbbe2d9e7a85c
+timeCreated: 1471836065
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 242 - 0
Unity/Assets/Editor/BehaviorTreeEditor/CustomArrayField.cs

@@ -0,0 +1,242 @@
+using Model;
+using UnityEditor;
+using UnityEngine;
+using Object = UnityEngine.Object;
+
+namespace MyEditor
+{
+	public static class CustomArrayField
+	{
+		public static int[] IntArrFieldValue(ref bool foldIntArr, string fieldDesc, int[] oldValue)
+		{
+			if (oldValue == null)
+			{
+				oldValue = new int[0];
+			}
+			int[] newValue = oldValue;
+
+			foldIntArr = EditorGUILayout.Foldout(foldIntArr, fieldDesc);
+			if (foldIntArr)
+			{
+				int size = EditorGUILayout.IntField("Size", oldValue.Length);
+
+				newValue = new int[size];
+				if (size >= oldValue.Length)
+				{
+					for (int i = 0; i < oldValue.Length; i++)
+					{
+						newValue[i] = EditorGUILayout.IntField(i.ToString(), oldValue[i]);
+					}
+					for (int i = oldValue.Length; i < size; i++)
+					{
+						newValue[i] = EditorGUILayout.IntField(i.ToString(), newValue[i]);
+					}
+				}
+				else if (size < oldValue.Length)
+				{
+					for (int i = 0; i < size; i++)
+					{
+						newValue[i] = EditorGUILayout.IntField(i.ToString(), oldValue[i]);
+					}
+				}
+			}
+			return newValue;
+		}
+
+		public static long[] LongArrFieldValue(ref bool foldIntArr, string fieldDesc, long[] oldValue)
+		{
+			if (oldValue == null)
+			{
+				oldValue = new long[0];
+			}
+			long[] newValue = oldValue;
+
+			foldIntArr = EditorGUILayout.Foldout(foldIntArr, fieldDesc);
+			if (foldIntArr)
+			{
+				int size = EditorGUILayout.IntField("Size", oldValue.Length);
+
+				newValue = new long[size];
+				if (size >= oldValue.Length)
+				{
+					for (int i = 0; i < oldValue.Length; i++)
+					{
+						newValue[i] = EditorGUILayout.LongField(i.ToString(), oldValue[i]);
+					}
+					for (int i = oldValue.Length; i < size; i++)
+					{
+						newValue[i] = EditorGUILayout.LongField(i.ToString(), newValue[i]);
+					}
+				}
+				else if (size < oldValue.Length)
+				{
+					for (int i = 0; i < size; i++)
+					{
+						newValue[i] = EditorGUILayout.LongField(i.ToString(), oldValue[i]);
+					}
+				}
+			}
+			return newValue;
+		}
+
+		public static float[] FloatArrFieldValue(ref bool foldIntArr, string fieldDesc, float[] oldValue)
+		{
+			if (oldValue == null)
+			{
+				oldValue = new float[0];
+			}
+			float[] newValue = oldValue;
+
+			foldIntArr = EditorGUILayout.Foldout(foldIntArr, fieldDesc);
+			if (foldIntArr)
+			{
+				int size = EditorGUILayout.IntField("Size", oldValue.Length);
+
+				newValue = new float[size];
+				if (size >= oldValue.Length)
+				{
+					for (int i = 0; i < oldValue.Length; i++)
+					{
+						newValue[i] = EditorGUILayout.FloatField(i.ToString(), oldValue[i]);
+					}
+					for (int i = oldValue.Length; i < size; i++)
+					{
+						newValue[i] = EditorGUILayout.FloatField(i.ToString(), newValue[i]);
+					}
+				}
+				else if (size < oldValue.Length)
+				{
+					for (int i = 0; i < size; i++)
+					{
+						newValue[i] = EditorGUILayout.FloatField(i.ToString(), oldValue[i]);
+					}
+				}
+			}
+			return newValue;
+		}
+
+		public static double[] DoubleArrFieldValue(ref bool foldIntArr, string fieldDesc, double[] oldValue)
+		{
+			if (oldValue == null)
+			{
+				oldValue = new double[0];
+			}
+			double[] newValue = oldValue;
+
+			foldIntArr = EditorGUILayout.Foldout(foldIntArr, fieldDesc);
+			if (foldIntArr)
+			{
+				int size = EditorGUILayout.IntField("Size", oldValue.Length);
+
+				newValue = new double[size];
+				if (size >= oldValue.Length)
+				{
+					for (int i = 0; i < oldValue.Length; i++)
+					{
+						newValue[i] = EditorGUILayout.DoubleField(i.ToString(), oldValue[i]);
+					}
+					for (int i = oldValue.Length; i < size; i++)
+					{
+						newValue[i] = EditorGUILayout.DoubleField(i.ToString(), newValue[i]);
+					}
+				}
+				else if (size < oldValue.Length)
+				{
+					for (int i = 0; i < size; i++)
+					{
+						newValue[i] = EditorGUILayout.DoubleField(i.ToString(), oldValue[i]);
+					}
+				}
+			}
+			return newValue;
+		}
+
+		public static string[] StringArrFieldValue(ref bool foldIntArr, string fieldDesc, string[] oldValue)
+		{
+			if (oldValue == null)
+			{
+				oldValue = new string[0];
+			}
+			string[] newValue = oldValue;
+
+			foldIntArr = EditorGUILayout.Foldout(foldIntArr, fieldDesc);
+			if (foldIntArr)
+			{
+				int size = EditorGUILayout.IntField("Size", oldValue.Length);
+
+				newValue = new string[size];
+				if (size >= oldValue.Length)
+				{
+					for (int i = 0; i < oldValue.Length; i++)
+					{
+						newValue[i] = EditorGUILayout.TextField(i.ToString(), oldValue[i]);
+					}
+					for (int i = oldValue.Length; i < size; i++)
+					{
+						newValue[i] = EditorGUILayout.TextField(i.ToString(), newValue[i]);
+					}
+				}
+				else if (size < oldValue.Length)
+				{
+					for (int i = 0; i < size; i++)
+					{
+						newValue[i] = EditorGUILayout.TextField(i.ToString(), oldValue[i]);
+					}
+				}
+			}
+			return newValue;
+		}
+
+		public static Object[] ObjectArrFieldValue(ref bool fold, string fieldDesc, Object[] oldValue, NodeFieldDesc desc)
+		{
+			if (oldValue == null)
+			{
+				oldValue = new Object[0];
+			}
+			Object[] newValue = oldValue;
+
+			fold = EditorGUILayout.Foldout(fold, fieldDesc);
+			if (fold)
+			{
+				int size = EditorGUILayout.IntField("Size", oldValue.Length);
+
+				newValue = new Object[size];
+				if (size >= oldValue.Length)
+				{
+					for (int i = 0; i < oldValue.Length; i++)
+					{
+						newValue[i] = EditorGUILayout.ObjectField(i.ToString(), oldValue[i], desc.type.GetElementType(), false);
+						if (TypeHelper.IsGameObjectArrayType(desc.type) &&
+						    !BehaviorTreeArgsDict.SatisfyCondition((GameObject) newValue[i], desc.constraintTypes))
+						{
+							newValue[i] = null;
+						}
+					}
+					for (int i = oldValue.Length; i < size; i++)
+					{
+						newValue[i] = EditorGUILayout.ObjectField(i.ToString(), newValue[i], desc.type.GetElementType(), false);
+						if (TypeHelper.IsGameObjectArrayType(desc.type) &&
+						    !BehaviorTreeArgsDict.SatisfyCondition((GameObject) newValue[i], desc.constraintTypes))
+						{
+							newValue[i] = null;
+						}
+					}
+				}
+				else if (size < oldValue.Length)
+				{
+					for (int i = 0; i < size; i++)
+					{
+						newValue[i] = EditorGUILayout.ObjectField(i.ToString(), oldValue[i], desc.type.GetElementType(), false);
+						if (TypeHelper.IsGameObjectArrayType(desc.type) &&
+						    !BehaviorTreeArgsDict.SatisfyCondition((GameObject) newValue[i], desc.constraintTypes))
+						{
+							newValue[i] = null;
+						}
+					}
+				}
+			}
+
+			return newValue;
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/CustomArrayField.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 5df2f5bafc6b6ac4a9ea1c1fb78fab83
+timeCreated: 1457606848
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 9 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Event.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 3a902cbd90500f548bc105b7137ec700
+folderAsset: yes
+timeCreated: 1471833564
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 14 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeAfterChangeNodeTypeEvent_SelectNode.cs

@@ -0,0 +1,14 @@
+using Model;
+
+namespace MyEditor
+{
+	[Event(EventIdType.BehaviorTreeAfterChangeNodeType)]
+	public class BehaviorTreeAfterChangeNodeTypeEvent_SelectNode: IEvent
+	{
+		public void Run()
+		{
+			NodeDesigner dstNode = BTEditorWindow.Instance.GraphDesigner.RootNode;
+			BTEditorWindow.Instance.OnSelectNode(dstNode.NodeData, dstNode);
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeAfterChangeNodeTypeEvent_SelectNode.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 4e86e5aa0b95e6a44ac642fdc8360fbb
+timeCreated: 1471924076
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 13 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeClickNodeEvent_SelectNode.cs

@@ -0,0 +1,13 @@
+using Model;
+
+namespace MyEditor
+{
+	[Event(EventIdType.BehaviorTreeClickNode)]
+	public class BehaviorTreeClickNodeEvent_SelectNode: IEvent<NodeDesigner>
+	{
+		public void Run(NodeDesigner dstNode)
+		{
+			BTEditorWindow.Instance.OnSelectNode(dstNode.NodeData, dstNode);
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeClickNodeEvent_SelectNode.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: fa2ea9bc3d790404abce044731b65f71
+timeCreated: 1471855717
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 13 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeConnectStateEvent_HandleConnectLines.cs

@@ -0,0 +1,13 @@
+using Model;
+
+namespace MyEditor
+{
+	[Event(EventIdType.BehaviorTreeConnectState)]
+	public class BehaviorTreeConnectStateEvent_HandleConnectLines: IEvent<NodeDesigner, State>
+	{
+		public void Run(NodeDesigner nodeDesigner, State state)
+		{
+			BTEditorWindow.Instance.onStartConnect(nodeDesigner, state);
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeConnectStateEvent_HandleConnectLines.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 6460dd840fc43414082566badbe8e643
+timeCreated: 1471936138
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 13 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeCreateNodeEvent_SelectNode.cs

@@ -0,0 +1,13 @@
+using Model;
+
+namespace MyEditor
+{
+	[Event(EventIdType.BehaviorTreeCreateNode)]
+	public class BehaviorTreeCreateNodeEvent_SelectNode: IEvent<NodeDesigner>
+	{
+		public void Run(NodeDesigner dstNode)
+		{
+			BTEditorWindow.Instance.OnSelectNode(dstNode.NodeData, dstNode);
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeCreateNodeEvent_SelectNode.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 4fcb8d64039181d4f9b4757e526985c3
+timeCreated: 1471924076
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 13 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeMouseInNodeEvent_HandleOperate.cs

@@ -0,0 +1,13 @@
+using Model;
+
+namespace MyEditor
+{
+	[Event(EventIdType.BehaviorTreeMouseInNode)]
+	public class BehaviorTreeMouseInNodeEvent_HandleOperate: IEvent<BehaviorNodeData, NodeDesigner>
+	{
+		public void Run(BehaviorNodeData nodeData, NodeDesigner nodeDesigner)
+		{
+			BTEditorWindow.Instance.onMouseInNode(nodeData, nodeDesigner);
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeMouseInNodeEvent_HandleOperate.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: b47f027d4544cfe4a90eee3dfbc43467
+timeCreated: 1471935347
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 14 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeNewCreateClickEvent_CreateNode.cs

@@ -0,0 +1,14 @@
+using Model;
+using UnityEngine;
+
+namespace MyEditor
+{
+	[Event(EventIdType.BehaviorTreePropertyDesignerNewCreateClick)]
+	public class BehaviorTreeNewCreateClickEvent_CreateNode: IEvent<string, Vector2>
+	{
+		public void Run(string name, Vector2 pos)
+		{
+			BTEditorWindow.Instance.onCreateNode(name, pos);
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeNewCreateClickEvent_CreateNode.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: ed445ef8856006f4998ca80b4aac91ff
+timeCreated: 1471924726
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 20 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeOpenEditorEvent_SelectNode.cs

@@ -0,0 +1,20 @@
+using Model;
+using UnityEngine;
+
+namespace MyEditor
+{
+	[Event(EventIdType.BehaviorTreeOpenEditor)]
+	public class BehaviorTreeOpenEditorEvent_SelectNode: IEvent
+	{
+		public void Run()
+		{
+			NodeDesigner dstNode = BTEditorWindow.Instance.onCreateTree();
+			if (dstNode == null)
+			{
+				Debug.LogError($"RootNode can not be null");
+				return;
+			}
+			BTEditorWindow.Instance.OnSelectNode(dstNode.NodeData, dstNode);
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeOpenEditorEvent_SelectNode.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 31b3074132b719a4398e25918a28d775
+timeCreated: 1471854631
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 13 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeOpenEditorEvent_SelectTree.cs

@@ -0,0 +1,13 @@
+using Model;
+
+namespace MyEditor
+{
+	[Event(EventIdType.BehaviorTreeOpenEditor)]
+	public class BehaviorTreeOpenEditorEvent_SelectTree: IEvent
+	{
+		public void Run()
+		{
+			//BTEditorWindow.Instance.onSelectTree();
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeOpenEditorEvent_SelectTree.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 94b95889faab35842a12f6f1107ea71d
+timeCreated: 1471851414
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 13 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeOpenEditorEvent_UpdatePropList.cs

@@ -0,0 +1,13 @@
+using Model;
+
+namespace MyEditor
+{
+	[Event(EventIdType.BehaviorTreeOpenEditor)]
+	public class BehaviorTreeOpenEditorEvent_UpdatePropList: IEvent
+	{
+		public void Run()
+		{
+			BTEditorWindow.Instance.onUpdatePropList();
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeOpenEditorEvent_UpdatePropList.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 44203aa133917cd48a10fd9a1cef3e01
+timeCreated: 1471854631
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 14 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeReplaceClickEvent_ReplaceNode.cs

@@ -0,0 +1,14 @@
+using Model;
+using UnityEngine;
+
+namespace MyEditor
+{
+	[Event(EventIdType.BehaviorTreeReplaceClick)]
+	public class BehaviorTreeReplaceClickEvent_ReplaceNode: IEvent<string, Vector2>
+	{
+		public void Run(string name, Vector2 pos)
+		{
+			BTEditorWindow.Instance.onChangeNodeType(name, pos);
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeReplaceClickEvent_ReplaceNode.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 6833ca6aaa4da864eb2f86ecff2b80bf
+timeCreated: 1471937253
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 13 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeRightDesignerDragEvent_ModifyRightBorder.cs

@@ -0,0 +1,13 @@
+using Model;
+
+namespace MyEditor
+{
+	[Event(EventIdType.BehaviorTreeRightDesignerDrag)]
+	public class BehaviorTreeRightDesignerDragEvent_ModifyRightBorder: IEvent<float>
+	{
+		public void Run(float deltaX)
+		{
+			BTEditorWindow.Instance.onDraggingRightDesigner(deltaX);
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeRightDesignerDragEvent_ModifyRightBorder.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 993b72d69dfd5d74eb3e348bb13090f3
+timeCreated: 1473063257
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 20 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeRunTreeEvent_ShowDebugInfo.cs

@@ -0,0 +1,20 @@
+using System.Collections.Generic;
+using Model;
+
+namespace MyEditor
+{
+	[Event(EventIdType.BehaviorTreeRunTreeEvent)]
+	public class BehaviorTreeRunTreeEvent_ShowDebugInfo: IEvent<BehaviorTree, List<long>>
+	{
+		public void Run(BehaviorTree tree, List<long> pathList)
+		{
+			if (BTEntity.Instance.BehaviorTreeConfig != null)
+			{
+				BTEntity.Instance.ClearDebugState();
+				BTEntity.Instance.GetComponent<BTDebugComponent>().TreePathList.Add(pathList);
+				BTEntity.Instance.GetComponent<BTDebugComponent>().BehaviorTree = tree;
+				BTEntity.Instance.SetDebugState(pathList);
+			}
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Event/BehaviorTreeRunTreeEvent_ShowDebugInfo.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: ddb7b97e3d06c2a478e896aed128905d
+timeCreated: 1471418167
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 160 - 0
Unity/Assets/Editor/BehaviorTreeEditor/FoldoutNode.cs

@@ -0,0 +1,160 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace MyEditor
+{
+	public class FoldoutNode //折叠的节点
+	{
+		public string folderName { get; set; }
+
+		public delegate void DelegateMethod(FoldoutNode self);
+
+		private readonly DelegateMethod mCallback;
+
+		public string Text { get; }
+
+		public bool Hide { get; set; } = false;
+
+		public bool Select { get; set; } = false;
+
+		public int Depth { get; set; }
+
+		public FoldoutNode(string text, DelegateMethod callback = null)
+		{
+			this.Text = text;
+			mCallback = callback;
+		}
+
+		public void Draw()
+		{
+			if (!this.Hide)
+			{
+				GUILayout.BeginHorizontal();
+				GUILayout.Space(15 * this.Depth);
+
+				string str = "";
+				if (this.Select)
+				{
+					str = str + "[" + this.Text + "]";
+				}
+				else
+				{
+					str = str + this.Text;
+				}
+				if (GUILayout.Button(str, GUI.skin.GetStyle("Label")))
+				{
+					mCallback.Invoke(this);
+				}
+				GUILayout.EndHorizontal();
+			}
+		}
+	}
+
+	public class FoldoutFolder //折叠的目录
+	{
+		public delegate void DelegateMethod(FoldoutFolder self);
+
+		private readonly DelegateMethod mCallback;
+
+		public string Text { get; }
+
+		public bool Hide { get; set; }
+
+		public bool Fold { get; set; }
+
+		public int Depth { get; set; }
+
+		public bool Select { get; set; } = false;
+
+		public List<FoldoutFolder> Folders { get; } = new List<FoldoutFolder>();
+
+		public List<FoldoutNode> Nodes { get; } = new List<FoldoutNode>();
+
+		public FoldoutFolder(string text, DelegateMethod callback = null)
+		{
+			this.Text = text;
+			mCallback = callback;
+		}
+
+		//添加折叠
+		public FoldoutFolder AddFolder(string text, DelegateMethod callback)
+		{
+			FoldoutFolder folder = new FoldoutFolder(text, callback);
+			this.Folders.Add(folder);
+			folder.Depth = this.Depth + 1;
+			return folder;
+		}
+
+		//添加叶子节点
+		public FoldoutNode AddNode(string folderName, string text, FoldoutNode.DelegateMethod callback)
+		{
+			FoldoutNode node = new FoldoutNode(text, callback);
+			node.folderName = folderName;
+			this.Nodes.Add(node);
+			node.Depth = this.Depth + 1;
+			return node;
+		}
+
+		public FoldoutNode FindNode(string text)
+		{
+			foreach (FoldoutNode node in this.Nodes)
+			{
+				if (node.Text == text)
+				{
+					return node;
+				}
+			}
+			return null;
+		}
+
+		public FoldoutFolder FindFolder(string text)
+		{
+			foreach (FoldoutFolder folder in this.Folders)
+			{
+				if (folder.Text == text)
+				{
+					return folder;
+				}
+			}
+			return null;
+		}
+
+		public void Draw()
+		{
+			GUILayout.BeginHorizontal();
+			GUILayout.Space(15 * this.Depth);
+
+			string str = "+";
+			if (this.Fold)
+			{
+				str = " -";
+			}
+			if (this.Select)
+			{
+				str = str + "[" + this.Text + "]";
+			}
+			else
+			{
+				str = str + this.Text;
+			}
+			if (GUILayout.Button(str, GUI.skin.GetStyle("Label")))
+			{
+				this.Fold = !this.Fold;
+				mCallback.Invoke(this);
+			}
+			GUILayout.EndHorizontal();
+
+			if (this.Fold)
+			{
+				foreach (FoldoutFolder folder in this.Folders)
+				{
+					folder.Draw();
+				}
+				foreach (FoldoutNode node in this.Nodes)
+				{
+					node.Draw();
+				}
+			}
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/FoldoutNode.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 364f87a660f33ef41aaa7d9c89905b08
+timeCreated: 1459149729
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 782 - 0
Unity/Assets/Editor/BehaviorTreeEditor/GraphDesigner.cs

@@ -0,0 +1,782 @@
+using System;
+using System.Collections.Generic;
+using Model;
+using UnityEditor;
+using UnityEngine;
+
+namespace MyEditor
+{
+	public enum State
+	{
+		Normal, //普通
+		Shift, //正在交换位置
+		Ctrl, //正在移动位置
+		Drag, //正在拖拽节点
+		ConnectLeft, //正在连线左
+		ConnectRight //正在连线右
+	}
+
+	public class GraphDesigner: Editor
+	{
+		public State mState = State.Normal;
+
+		/// 绘图相关
+		private Rect mBorderRect; //边框
+
+		private Rect mGraphRect = new Rect(0, 0, 2000, 2000); //绘图区域
+		private float mLeftWidth = 380f;
+		private float mRightWidth;
+		private Vector2 mScrollPosition = Vector2.zero;
+
+		public void Draw(Rect windowRect)
+		{
+			mBorderRect = new Rect(mLeftWidth, 0, windowRect.width - mLeftWidth - 16 - mRightWidth, windowRect.height - 16);
+			mScrollPosition = GUI.BeginScrollView(new Rect(mBorderRect.x, mBorderRect.y, mBorderRect.width + 15f, mBorderRect.height + 15f), mScrollPosition,
+			                                      mGraphRect, true, true);
+
+			DrawBackground();
+			DrawConnectingLine();
+			DrawNodes();
+
+			GUI.EndScrollView();
+
+			//更改鼠标光标
+			if (mDragingLeftBorder || mDragingRightBorder || mState == State.Drag)
+			{
+				Cursor.visible = false;
+				DrawMouseIcon("DragIcon");
+			}
+			else if (mState == State.Shift || mState == State.Ctrl)
+			{
+				Cursor.visible = false;
+				DrawMouseIcon("ShiftIcon");
+			}
+			else
+			{
+				Cursor.visible = true;
+			}
+
+			HandleEvents();
+			CalcGraphRect();
+		}
+
+		public void DrawNodes()
+		{
+			RootNode?.Draw();
+			foreach (NodeDesigner node in mDetachedNodes)
+			{
+				node.Draw();
+			}
+		}
+
+		//正在连线
+		public void DrawConnectingLine()
+		{
+			if (mSelectedNode == null)
+			{
+				return;
+			}
+			Vector2 curPos = Event.current.mousePosition; //MousePosToGraphPos(Event.current.mousePosition);
+			if (mState == State.ConnectLeft)
+			{
+				BTDesignerUtility.DrawConnection(mSelectedNode.LeftPos, curPos);
+			}
+			if (mState == State.ConnectRight)
+			{
+				BTDesignerUtility.DrawConnection(mSelectedNode.RightPos, curPos);
+			}
+		}
+
+		private Vector2 mMousePos = Vector2.zero;
+		private Vector2 mSrcOffset = Vector2.zero;
+		private bool mLock = true;
+		private bool mDragingLeftBorder;
+		private bool mDragingRightBorder;
+
+		public void HandleEvents()
+		{
+			Event e = Event.current;
+			switch (e.type)
+			{
+				case EventType.MouseDown:
+					GUI.FocusControl("");
+					mMousePos = e.mousePosition;
+					if (!BTEditorWindow.windowRect.Contains(mMousePos))
+					{
+						BTEditorWindow.Instance.CloseSubWin();
+					}
+					if (BTEditorWindow.windowRect.Contains(mMousePos) && BTEditorWindow.IsShowSubWin)
+					{
+						break;
+					}
+					//单击选中
+					if (e.button == 0)
+					{
+						CheckMouseInNode();
+					}
+					//双击折叠
+					if (e.button == 0 && e.clickCount == 2 && mState != State.ConnectLeft && mState != State.ConnectRight)
+					{
+						mSelectedNode?.Fold();
+						CalcGraphRect();
+					}
+					//右键
+					if (e.button == 1)
+					{
+						//取消选中
+						mSelectedNode?.onSelect(false);
+						mSelectedNode = null;
+						//重新选中
+						CheckMouseInNode();
+
+						//右键菜单
+						PopMenu();
+					}
+					if (e.button == 0 && e.mousePosition.x < mLeftWidth + 30 && e.mousePosition.x > mLeftWidth)
+					{
+						mDragingLeftBorder = true;
+					}
+					if (e.button == 0 && e.mousePosition.x < mLeftWidth + mBorderRect.width && e.mousePosition.x > mLeftWidth + mBorderRect.width - 30)
+					{
+						mDragingRightBorder = true;
+					}
+
+					break;
+				case EventType.MouseUp:
+					if (BTEditorWindow.windowRect.Contains(mMousePos) && BTEditorWindow.IsShowSubWin)
+					{
+						break;
+					}
+					if (e.button == 0 && e.shift)
+					{
+						mSelectedNode.Offset = mSrcOffset;
+						mSelectedNode.Parent.AutoSort();
+						CheckMouseInNode();
+					}
+					if (e.button == 0)
+					{
+						CheckMouseInNode();
+					}
+					mState = State.Normal;
+					mDragingLeftBorder = false;
+					mDragingRightBorder = false;
+					break;
+				case EventType.MouseDrag:
+					//中键
+					if (e.button == 2 || (e.button == 0 && e.alt))
+					{
+						mScrollPosition.x -= e.delta.x;
+						mScrollPosition.y -= e.delta.y;
+						mState = State.Normal;
+						return;
+					}
+					if (e.button == 0 && e.shift)
+					{
+						if (mSelectedNode != null)
+						{
+							mSrcOffset = mSelectedNode.Offset;
+							mSelectedNode.onDrag(e.delta);
+							mState = State.Shift;
+						}
+
+						return;
+					}
+					if (e.button == 0 && e.control)
+					{
+						if (mSelectedNode != null)
+						{
+							mSrcOffset = mSelectedNode.Offset;
+							mSelectedNode.onDrag(e.delta);
+							mState = State.Ctrl;
+						}
+						return;
+					}
+					if (mDragingLeftBorder)
+					{
+						mLeftWidth += e.delta.x;
+						return;
+					}
+					if (mDragingRightBorder)
+					{
+						mRightWidth -= e.delta.x;
+						Game.Scene.GetComponent<EventComponent>().Run(EventIdType.BehaviorTreeRightDesignerDrag, e.delta.x);
+						return;
+					}
+
+					//左键
+					if (e.button == 0 && (e.control || !mLock))
+					{
+						if (mSelectedNode != null)
+						{
+							mSelectedNode.onDrag(e.delta);
+							mState = State.Drag;
+							DrawMouseIcon("DragIcon");
+						}
+					}
+					break;
+				case EventType.KeyUp:
+					//F1自动排序
+					if (e.keyCode == KeyCode.F1)
+					{
+						RootNode?.AutoSort();
+						RootNode.UpdateChildren();
+					}
+					if (e.keyCode == KeyCode.F2)
+					{
+						mLock = !mLock;
+						if (mLock)
+						{
+							BehaviorTreeTipsHelper.ShowMessage("节点位置已锁定");
+						}
+						else
+						{
+							BehaviorTreeTipsHelper.ShowMessage("节点位置已解锁");
+						}
+					}
+					if (e.keyCode == KeyCode.Delete)
+					{
+						RemoveNode();
+					}
+					break;
+				case EventType.MouseMove:
+					DrawMouseIcon("DragIcon2");
+					break;
+			}
+		}
+
+		public void DrawMouseIcon(string resName)
+		{
+			GUI.DrawTexture(new Rect(Event.current.mousePosition.x - 10, Event.current.mousePosition.y - 20, 17, 20),
+			                BTDesignerUtility.GetTexture(resName));
+		}
+
+		public void CheckMouseInNode()
+		{
+			Vector2 pos = MousePosToGraphPos(Event.current.mousePosition);
+			RootNode?.OnMousePos(pos);
+			for (int i = 0; i < mDetachedNodes.Count; i++)
+			{
+				NodeDesigner node = mDetachedNodes[i];
+				node.OnMousePos(pos);
+			}
+		}
+
+		public void CalcGraphRect()
+		{
+			if (RootNode == null)
+			{
+				mGraphRect.width = mBorderRect.width;
+				mGraphRect.height = mBorderRect.height;
+			}
+			else
+			{
+				mGraphRect = RootNode.Size;
+				mGraphRect.width += RootNode.Width * 4;
+				mGraphRect.height += RootNode.Height;
+				if (mGraphRect.width < mBorderRect.width)
+				{
+					mGraphRect.width = mBorderRect.width;
+				}
+				if (mGraphRect.height < mBorderRect.height)
+				{
+					mGraphRect.height = mBorderRect.height;
+				}
+
+				RootNode.Pos.x = RootNode.Width;
+				RootNode.Pos.y = RootNode.Size.height / 2 + RootNode.Height / 2;
+				RootNode.UpdateChildrenPos(RootNode.Offset);
+			}
+		}
+
+		public Vector2 MousePosToGraphPos(Vector2 mousePos)
+		{
+			Vector2 graphPos = new Vector2();
+			graphPos.x = mousePos.x + mScrollPosition.x - mLeftWidth;
+			graphPos.y = mousePos.y + mScrollPosition.y;
+			return graphPos;
+		}
+
+		public Vector2 CenterPosInBorder()
+		{
+			Vector2 pos = new Vector2();
+			pos.x = mScrollPosition.x + mBorderRect.width / 2;
+			pos.y = mScrollPosition.y + mBorderRect.height / 2;
+			return pos;
+		}
+
+		public void DrawBackground()
+		{
+			float width = 15f;
+			Texture2D bgTex = BTDesignerUtility.GetTexture("Bg");
+			GUI.DrawTexture(new Rect(0, 0, mGraphRect.width, mGraphRect.height), bgTex);
+
+			Texture2D lineTex = BTDesignerUtility.GetTexture("BgLine");
+			for (int i = 0; i < mGraphRect.width / width; i++)
+			{
+				GUI.DrawTexture(new Rect(width * i, 0, 1f, mGraphRect.height), lineTex);
+			}
+			for (int j = 0; j < mGraphRect.height / width; j++)
+			{
+				GUI.DrawTexture(new Rect(0, width * j, mGraphRect.width, 1f), lineTex);
+			}
+		}
+
+		public List<string> GetCanRepalceList()
+		{
+			List<string> result = new List<string>();
+			if (mSelectedNode != null)
+			{
+				if (mSelectedNode.NodeData.Proto.classify == NodeClassifyType.Root.ToString() ||
+				    BTEntity.Instance.CurTree.Root.Id == mSelectedNode.NodeData.Id)
+				{
+					List<NodeMeta> list = BTEntity.Instance.Classify2NodeProtoList[NodeClassifyType.Root.ToString()];
+					foreach (NodeMeta nodeType in list)
+					{
+						result.Add(nodeType.name);
+						// menu.AddItem(new GUIContent(string.Format("{0}/{1}", "替换为", nodeType.name)), false, new GenericMenu.MenuFunction2(this.ChangeNodeType), nodeType.name);
+					}
+				}
+				else
+				{
+					// NodeChildLimitType nodeChildLimitType = mSelectedNode.NodeData.IsLeaf() ? NodeChildLimitType.All : NodeChildLimitType.WithChild;
+					List<NodeMeta> canSubtituteList = BTEntity.Instance.AllNodeProtoList;
+					canSubtituteList.Sort(CompareShowName);
+					foreach (NodeMeta nodeType in canSubtituteList)
+					{
+						if (nodeType.classify == NodeClassifyType.Root.ToString())
+						{
+							continue;
+						}
+						// menu.AddItem(new GUIContent(string.Format("{0}/{1}", "替换为", nodeType.name)), false, new GenericMenu.MenuFunction2(this.ChangeNodeType), nodeType.name);
+						if (mSelectedNode.NodeData.Proto.child_limit <= nodeType.child_limit)
+						{
+							result.Add(nodeType.name);
+						}
+					}
+				}
+			}
+			return result;
+		}
+
+		public List<string> GetCanCreateList()
+		{
+			List<string> result = new List<string>();
+
+			foreach (KeyValuePair<string, List<NodeMeta>> kv in BTEntity.Instance.Classify2NodeProtoList)
+			{
+				string classify = kv.Key;
+				List<NodeMeta> nodeProtoList = kv.Value;
+				nodeProtoList.Sort(CompareShowName);
+				if (classify == NodeClassifyType.Root.ToString())
+				{
+					continue;
+				}
+				foreach (NodeMeta node in nodeProtoList)
+				{
+					if (mSelectedNode != null && mSelectedNode.NodeData.Children.Count < mSelectedNode.NodeData.Proto.child_limit)
+					{
+						result.Add(node.name);
+					}
+				}
+			}
+			return result;
+		}
+
+		///菜单相关
+		public void PopMenu()
+		{
+			GenericMenu menu = new GenericMenu();
+
+			menu.AddItem(new GUIContent("创建子节点"), false, this.PopUpCreate);
+			menu.AddItem(new GUIContent("替换当前节点"), false, this.PopUpReplace);
+			string selectNodeName = BTEntity.Instance.selectNodeName;
+			string selectNodeType = BTEntity.Instance.selectNodeType;
+			if (mSelectedNode != null && selectNodeName != "")
+			{
+				if (selectNodeType != NodeClassifyType.Root.ToString() && mSelectedNode.NodeData.Children.Count < mSelectedNode.NodeData.Proto.child_limit)
+				{
+					menu.AddItem(new GUIContent(string.Format($"新建{selectNodeName}")), false, this.CreateNode);
+				}
+				else
+				{
+					menu.AddDisabledItem(new GUIContent("新建"));
+				}
+				if (mSelectedNode.NodeData.Proto.classify == NodeClassifyType.Root.ToString())
+				{
+					string menuName = string.Format($"替换成{selectNodeName}");
+					if (selectNodeType == NodeClassifyType.Root.ToString())
+					{
+						menu.AddItem(new GUIContent(menuName), false, this.ChangeNodeType);
+					}
+					else
+					{
+						menu.AddDisabledItem(new GUIContent(menuName));
+					}
+				}
+				else
+				{
+					string menuName = string.Format($"替换成{selectNodeName}");
+					NodeClassifyType value = (NodeClassifyType) Enum.Parse(typeof(NodeClassifyType), selectNodeType);
+					int count = NodeMetaHelper.NodeTypeCountDict[value];
+					if (selectNodeType == NodeClassifyType.Root.ToString() || (count == 0 && mSelectedNode.NodeData.Proto.child_limit > 0))
+					{
+						menu.AddDisabledItem(new GUIContent(menuName));
+					}
+					else
+					{
+						menu.AddItem(new GUIContent(menuName), false, this.ChangeNodeType);
+					}
+				}
+			}
+			else
+			{
+				menu.AddDisabledItem(new GUIContent("新建"));
+				menu.AddDisabledItem(new GUIContent("替换"));
+			}
+			menu.AddItem(new GUIContent("自动排序"), false, this.AutoSort);
+			menu.AddItem(new GUIContent("复制"), false, this.CopyNode);
+			menu.AddItem(new GUIContent("剪切"), false, this.CutNode);
+			menu.AddItem(new GUIContent("粘贴"), false, this.PasteNode);
+			menu.AddItem(new GUIContent("删除节点"), false, this.RemoveNode);
+			menu.ShowAsContext();
+		}
+
+		private void PopUpCreate()
+		{
+			BTEditorWindow.Instance.ShowSubWin(mMousePos, SubWinType.CreateNode);
+		}
+
+		private void PopUpReplace()
+		{
+			BTEditorWindow.Instance.ShowSubWin(mMousePos, SubWinType.ReplaceNode);
+		}
+
+		private static int CompareShowName(NodeMeta nodeType1, NodeMeta nodeType2)
+		{
+			if (string.IsNullOrEmpty(nodeType1.name) || string.IsNullOrEmpty(nodeType2.name))
+			{
+				Log.Error("字符串输入参数有误");
+			}
+			return String.CompareOrdinal(nodeType1.name, nodeType2.name);
+		}
+
+		public void AutoSort()
+		{
+			RootNode?.AutoSort();
+		}
+		
+		private void CreateNode()
+		{
+			NodeMeta nodeProto = BTEntity.Instance.GetNodeMeta(BTEntity.Instance.selectNodeName);
+			BehaviorNodeData nodeData = BTEntity.Instance.CreateNode((int) BTEntity.Instance.CurTree.Id, nodeProto.name);
+			CreateNode(nodeData, MousePosToGraphPos(mMousePos));
+		}
+
+		public void CopyNode()
+		{
+			mCutNode = null;
+			mCopyNode = mSelectedNode;
+			if (mSelectedNode != null)
+			{
+				BehaviorTreeTipsHelper.ShowMessage("复制节点" + mSelectedNode.NodeData.Id);
+			}
+		}
+
+		public void CutNode()
+		{
+			mCopyNode = null;
+			mCutNode = mSelectedNode;
+			if (mSelectedNode != null)
+			{
+				BehaviorTreeTipsHelper.ShowMessage("剪切节点" + mSelectedNode.NodeData.Id);
+			}
+		}
+
+		public void PasteNode()
+		{
+			if (mCutNode != null && mCutNode != mSelectedNode)
+			{
+				ConnectNode(mCutNode, mSelectedNode);
+			}
+			if (mCopyNode != null && mCopyNode != mSelectedNode)
+			{
+				BehaviorNodeData data = BTEntity.Instance.CopyNode(mCopyNode.NodeData);
+				BTEntity.Instance.ResetTreeId();
+				NodeDesigner node = CreateNode(data, Vector2.zero);
+				ConnectNode(node, mSelectedNode);
+			}
+		}
+
+		public void RemoveConnection()
+		{
+			if (mSelectedNode == null || mSelectedNode == RootNode)
+			{
+				return;
+			}
+
+			foreach (NodeDesigner node in mDetachedNodes)
+			{
+				if (node == mSelectedNode)
+				{
+					return;
+				}
+			}
+			mSelectedNode.Parent?.RemoveChild(mSelectedNode);
+			mDetachedNodes.Add(mSelectedNode);
+		}
+
+		public void RemoveNode()
+		{
+			if (mSelectedNode == null)
+			{
+				return;
+			}
+			if (mSelectedNode.Parent != null)
+			{
+				mSelectedNode.Parent.RemoveChild(mSelectedNode);
+				return;
+			}
+			mDetachedNodes.Remove(mSelectedNode);
+			BTEntity.Instance.ResetTreeId();
+		}
+
+		private void ChangeNodeType()
+		{
+			ChangeNodeType(BTEntity.Instance.selectNodeName);
+		}
+
+		//有待优化
+		private void ChangeNodeType(object obj)
+		{
+			string nodeType = (string) obj;
+			NodeMeta nodeProto = BTEntity.Instance.GetNodeMeta(nodeType);
+			BehaviorNodeData nodeData = BTEntity.Instance.CreateNode((int) BTEntity.Instance.CurTree.Id, nodeProto.name);
+			NodeDesigner oldNode = mSelectedNode;
+			NodeDesigner newNode = new NodeDesigner(nodeData);
+
+			if (oldNode == RootNode)
+			{
+				newNode.NodeData.Id = RootNode.NodeData.Id;
+				RootNode = newNode;
+				BehaviorTreeData oldTree = BTEntity.Instance.CurTree;
+				BehaviorTreeData newTree = new BehaviorTreeData(oldTree.Id);
+				newTree.classify = oldTree.classify;
+				newTree.Root = nodeData;
+				BTEntity.Instance.CurTree = newTree;
+			}
+			else
+			{
+				int idx = oldNode.Parent.Children.IndexOf(oldNode);
+				oldNode.Parent.AddChild(newNode, idx);
+				oldNode.Parent.RemoveChild(oldNode);
+			}
+
+			foreach (NodeDesigner child in oldNode.Children)
+			{
+				newNode.AddChild(child);
+			}
+			BTEntity.Instance.ResetTreeId();
+			Game.Scene.GetComponent<EventComponent>().Run(EventIdType.BehaviorTreeAfterChangeNodeType);
+		}
+
+		public void onChangeNodeType(params object[] list)
+		{
+			ChangeNodeType(list[0]);
+		}
+
+		/// 节点逻辑相关
+		private readonly List<NodeDesigner> mDetachedNodes = new List<NodeDesigner>();
+
+		private NodeDesigner mSelectedNode;
+		private NodeDesigner mCopyNode;
+		private NodeDesigner mCutNode;
+
+		public NodeDesigner RootNode { get; set; }
+
+		public NodeDesigner CreateNode(BehaviorNodeData nodeData, Vector2 pos)
+		{
+			NodeDesigner node = new NodeDesigner(nodeData);
+			node.Pos = pos == Vector2.zero? CenterPosInBorder() : pos;
+			if (mSelectedNode != null)
+			{
+				mSelectedNode.AddChild(node);
+				mSelectedNode.AutoSort();
+			}
+			else
+			{
+				mDetachedNodes.Add(node);
+			}
+			BTEntity.Instance.ResetTreeId();
+			Game.Scene.GetComponent<EventComponent>().Run(EventIdType.BehaviorTreeCreateNode, node);
+			return node;
+		}
+
+		/// 事件相关
+		public NodeDesigner onCreateTree(params object[] list)
+		{
+			if (BTEntity.Instance.CurTree == null)
+			{
+				Log.Error($"CurTree can not be null");
+				return null;
+			}
+			RootNode = new NodeDesigner(BTEntity.Instance.CurTree.Root);
+			CalcGraphRect();
+			return RootNode;
+		}
+
+		public void onSelectNode(params object[] list)
+		{
+			mSelectedNode?.onSelect(false);
+			mSelectedNode = (NodeDesigner) list[1];
+			mSelectedNode.onSelect(true);
+		}
+
+		public void onCreateNode(params object[] list)
+		{
+			string name = (string) list[0];
+			Vector2 pos = (Vector2) list[1];
+
+			NodeMeta nodeProto = BTEntity.Instance.GetNodeMeta(name);
+			BehaviorNodeData nodeData = BTEntity.Instance.CreateNode((int) BTEntity.Instance.CurTree.Id, nodeProto.name);
+			CreateNode(nodeData, pos);
+		}
+
+		public void onStartConnect(params object[] list)
+		{
+			NodeDesigner node = (NodeDesigner) list[0];
+			State state = (State) list[1];
+			if (node == RootNode && state == State.ConnectLeft) //根节点不让左连接
+			{
+				return;
+			}
+			mState = state;
+		}
+
+		public void onMouseInNode(params object[] list)
+		{
+			NodeDesigner dstNode = (NodeDesigner) list[1];
+			if (dstNode == mSelectedNode || dstNode == null)
+			{
+				return;
+			}
+			switch (mState)
+			{
+				case State.Normal:
+					ClickNode(dstNode);
+					break;
+				case State.Drag: break;
+				case State.Shift:
+					ShiftNode(dstNode);
+					break;
+				case State.Ctrl:
+					MoveNode(dstNode);
+					break;
+				case State.ConnectLeft:
+					ConnectNode(mSelectedNode, dstNode);
+					break;
+				case State.ConnectRight:
+					ConnectNode(dstNode, mSelectedNode);
+					break;
+			}
+		}
+
+		//src接到dst的子节点
+		public void ConnectNode(NodeDesigner srcNode, NodeDesigner dstNode)
+		{
+			if (srcNode == null || dstNode == null || !dstNode.NodeData.CanAddChild())
+			{
+				return;
+			}
+			if (srcNode.FindChild(dstNode))
+			{
+				//src有dst这个子节点不让连,避免死循环
+				//Log.Info("found child");
+				return;
+			}
+
+			NodeDesigner parent = srcNode.Parent;
+			if (parent != null)
+			{
+				parent.RemoveChild(srcNode);
+			}
+			dstNode.AddChild(srcNode);
+			dstNode.AutoSort();
+
+			mDetachedNodes.Remove(srcNode);
+		}
+
+		public void ClickNode(NodeDesigner dstNode)
+		{
+			Game.Scene.GetComponent<EventComponent>().Run(EventIdType.BehaviorTreeClickNode, dstNode);
+		}
+
+		public void ShiftNode(NodeDesigner dstNode)
+		{
+			Log.Info("shift node");
+
+			if (mSelectedNode == null)
+			{
+				return;
+			}
+			NodeDesigner node1 = dstNode;
+			NodeDesigner node2 = mSelectedNode;
+			NodeDesigner parent1 = node1.Parent;
+			NodeDesigner parent2 = node2.Parent;
+			//根节点不可交换
+			if (parent2 == null)
+			{
+				return;
+			}
+			//同父交换位置
+			if (parent1 == parent2)
+			{
+				parent1.RemoveChild(node2);
+				int idx = parent1.Children.IndexOf(node1);
+				parent1.AddChild(node2, idx);
+				parent1.AutoSort();
+				//BTEntity.GetInstance().ResetTreeId();
+			}
+
+			//             //不同父,插到node1的子节点
+			//             if (!node1.NodeData.CanAddChild())
+			//                 return;
+			// 
+			//             parent2.RemoveChild(node2);
+			//             parent2.AutoSort();
+			//             node1.AddChild(node2);
+			//             node1.AutoSort();
+			//             BTEntity.GetInstance().ResetTreeId();
+		}
+
+		public void MoveNode(NodeDesigner dstNode)
+		{
+			Log.Info("Move  node");
+
+			if (mSelectedNode == null)
+			{
+				return;
+			}
+			NodeDesigner node1 = dstNode;
+			NodeDesigner node2 = mSelectedNode;
+			NodeDesigner parent1 = node1.Parent;
+			NodeDesigner parent2 = node2.Parent;
+			//根节点不可交换
+			if (parent2 == null)
+			{
+				return;
+			}
+
+			//不同父,插到node1的子节点
+			if (!node1.NodeData.CanAddChild())
+			{
+				return;
+			}
+
+			parent2.RemoveChild(node2);
+			parent2.AutoSort();
+			node1.AddChild(node2);
+			node1.AutoSort();
+			//BTEntity.GetInstance().ResetTreeId();
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/GraphDesigner.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 834873f3d04ba7249a372bb9c5d2d705
+timeCreated: 1445249041
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 354 - 0
Unity/Assets/Editor/BehaviorTreeEditor/NodeDesigner.cs

@@ -0,0 +1,354 @@
+using System.Collections.Generic;
+using Model;
+using UnityEngine;
+
+namespace MyEditor
+{
+	public class NodeDesigner
+	{
+		private Texture2D mBoxHighLight;
+		private Texture2D mBoxSelectHighLight;
+		private bool isSelected;
+
+		public NodeDesignerProto DesignerData { get; set; }
+
+		public NodeDesigner(BehaviorNodeData data)
+		{
+			NodeData = data;
+			data.NodeDesigner = this;
+			DesignerData = new NodeDesignerProto();
+			Init();
+			UpdateChildren();
+		}
+
+		public List<NodeDesigner> Children { get; } = new List<NodeDesigner>();
+
+		public NodeDesigner Parent { get; set; }
+
+		public void UpdateChildren()
+		{
+			if (!DesignerData.fold)
+			{
+				this.Children.Clear();
+				foreach (BehaviorNodeData childData in NodeData.Children)
+				{
+					NodeDesigner child = new NodeDesigner(childData);
+					this.Children.Add(child);
+					child.Parent = this;
+				}
+			}
+			else
+			{
+				this.Children.Clear();
+				return;
+			}
+			UpdateChildrenPos(this.Offset);
+		}
+
+		public BehaviorNodeData NodeData { get; set; }
+
+		//坐标位置相关
+		public float Width;
+
+		public float Height;
+		public Vector2 Pos = Vector2.zero; //中心点
+
+		public Vector2 Offset
+		{
+			get
+			{
+				return new Vector2(DesignerData.x, DesignerData.y);
+			}
+			set
+			{
+				DesignerData.x = value.x;
+				DesignerData.y = value.y;
+			}
+		}
+
+		public Vector2 LeftPos //左边坐标
+		{
+			get
+			{
+				return new Vector2(Pos.x - Width / 2, Pos.y);
+			}
+		}
+
+		public Vector2 RightPos //右边坐标
+		{
+			get
+			{
+				return new Vector2(Pos.x + Width / 2, Pos.y);
+			}
+		}
+
+		public Rect Size;
+		
+		private Texture2D mBoxTex;
+		private Texture2D mLeftConnectTex;
+		private Texture2D mRightConnectTex;
+
+		public void Init()
+		{
+			NodeData.Proto = BTEntity.Instance.GetNodeMeta(NodeData.Name);
+			string[] arr = NodeData.Proto.style.Split('/');
+			string style = arr.Length > 0? arr[0] : "";
+			if (style == "")
+			{
+				switch (NodeData.Classify)
+				{
+					case "装饰节点":
+						style = "green";
+						break;
+					case "复合节点":
+						style = "blue";
+						break;
+					case "条件节点":
+						style = "orange";
+						break;
+				}
+				switch (NodeData.Name)
+				{
+					case "Sequence":
+						style = "blue";
+						break;
+					case "Selector":
+						style = "green";
+						break;
+					default:
+						style = "default";
+						break;
+				}
+			}
+			mBoxTex = BTDesignerUtility.GetTexture(style);
+			mBoxHighLight = BTDesignerUtility.GetTexture("HighLight");
+			mBoxSelectHighLight = BTDesignerUtility.GetTexture("SelectHighLight");
+
+			if (mBoxTex == null)
+			{
+				mBoxTex = BTDesignerUtility.GetTexture("default");
+			}
+			if (mBoxTex == null)
+			{
+				Log.Info("mBoxTex null " + NodeData.Id);
+			}
+			Width = mBoxTex.width / 2;
+			Height = mBoxTex.height / 2;
+
+			mLeftConnectTex = BTDesignerUtility.GetTexture("LeftConnect");
+			mRightConnectTex = BTDesignerUtility.GetTexture("RightConnect");
+		}
+
+		public void Draw()
+		{
+			foreach (NodeDesigner child in this.Children)
+			{
+				//先画子节点,让线条在最低层
+				BTDesignerUtility.DrawConnection(this.RightPos, child.LeftPos);
+				child.Draw();
+			}
+
+			//左链接
+			Texture2D tex = mLeftConnectTex;
+			Rect rect = new Rect(Pos.x - Width / 2 - tex.width / 6, Pos.y - tex.height / 4, tex.width / 2, tex.height / 2);
+			GUI.DrawTexture(rect, tex);
+			//右链接
+			if (NodeData.Proto.child_limit > 0)
+			{
+				tex = mRightConnectTex;
+				rect = new Rect(Pos.x + Width / 2 - tex.width / 6 * 2, Pos.y - tex.height / 4.1f, tex.width / 2, tex.height / 2);
+				GUI.DrawTexture(rect, tex);
+
+				if (NodeData.Children.Count > 0)
+				{
+					if (DesignerData.fold)
+					{
+						GUI.Label(new Rect(Pos.x + Width / 2 - 5f, Pos.y - 9f, tex.width, tex.height), "+");
+					}
+					else
+					{
+						GUI.Label(new Rect(Pos.x + Width / 2 - 8f, Pos.y - 9f, tex.width, tex.height), "—");
+					}
+				}
+			}
+
+			rect = new Rect(Pos.x - Width / 2, Pos.y - Height / 2, Width, Height);
+			GUI.DrawTexture(rect, mBoxTex);
+			if (isSelected)
+			{
+				GUI.DrawTexture(rect, mBoxSelectHighLight);
+			}
+			else if (BTEntity.Instance.IsHighLight(this.NodeData))
+			{
+				GUI.DrawTexture(rect, mBoxHighLight);
+			}
+
+			GUIStyle style = new GUIStyle();
+			style.normal.background = null;
+			style.normal.textColor = new Color(1, 1, 1);
+			style.fontSize = 15;
+			if (!this.isSelected)
+			{
+				style.clipping = TextClipping.Clip;
+			}
+			GUI.Label(new Rect(Pos.x - Width / 2 + 5f, Pos.y - Height / 3, Width - 10f, Height / 2), NodeData.Proto.name, style);
+
+			style.normal.textColor = new Color(0.8f, 0.8f, 0.8f);
+			style.fontSize = 12;
+			style.wordWrap = true;
+			string deprecatedDesc = NodeData.Proto.isDeprecated? $"({NodeData.Proto.deprecatedDesc})" : "";
+			GUI.Label(new Rect(Pos.x - Width / 2 + 6f, Pos.y, Width - 12f, Height / 2.1f), NodeData.Desc + deprecatedDesc, style);
+
+			tex = null;
+			switch (NodeData.NodeDeubgState)
+			{
+				case DebugState.True:
+					tex = BTDesignerUtility.GetTexture("Execute");
+					break;
+				//                 case DebugState.False:
+				//                     tex = BTDesignerUtility.GetTexture("False");
+				//                     break;
+				//                 case DebugState.Error:
+				//                     tex = BTDesignerUtility.GetTexture("Error");
+				//                     break;
+			}
+			if (tex != null)
+			{
+				GUI.DrawTexture(rect, tex);
+				//                 string time = System.DateTime.Now.ToString();
+				//                 GUI.Label(new Rect(Pos.x + Width / 2, Pos.y -20, Width - 12f, Height / 2.1f), time, style);
+			}
+		}
+
+		public void AddChild(NodeDesigner child, int index = -1)
+		{
+			index = index == -1? this.Children.Count : index;
+			this.Children.Insert(index, child);
+			child.Parent = this;
+			NodeData.AddChild(child.NodeData, index);
+		}
+
+		public void RemoveChild(NodeDesigner child)
+		{
+			this.Children.Remove(child);
+			child.Parent = null;
+			NodeData.RemoveChild(child.NodeData);
+		}
+
+		public void UpdateSize()
+		{
+			Size.width = Width * 1.5f;
+			Size.height = Height;
+			if (this.Children.Count == 0)
+			{
+				return;
+			}
+			foreach (NodeDesigner child in this.Children)
+			{
+				child.UpdateSize();
+			}
+
+			float max = 0;
+			foreach (NodeDesigner child in this.Children)
+			{
+				max = max < child.Size.width? child.Size.width : max;
+			}
+			Size.width += max;
+
+			Size.height = 0;
+			foreach (NodeDesigner child in this.Children)
+			{
+				Size.height += child.Size.height;
+			}
+		}
+
+		public void UpdateChildrenPos(Vector2 offset)
+		{
+			UpdateSize();
+			float y = this.Pos.y - this.Size.height / 2;
+			foreach (NodeDesigner child in this.Children)
+			{
+				child.Pos.x = this.Pos.x + Width * 1.5f + child.Offset.x;
+				child.Pos.y = y + child.Size.height / 2 + child.Offset.y;
+				y += child.Size.height;
+				child.UpdateChildrenPos(offset);
+			}
+		}
+
+		public void OnMousePos(Vector2 mouse)
+		{
+			//判断是否被点中
+			if (!isSelected && mouse.x > Pos.x - Width / 2 - 30f && mouse.x < Pos.x + Width / 2 + 30f && mouse.y > Pos.y - Height / 2 &&
+			    mouse.y < Pos.y + Height / 2)
+			{
+				Game.Scene.GetComponent<EventComponent>().Run(EventIdType.BehaviorTreeMouseInNode, NodeData, this);
+			}
+			//并判断是否点中了连线柄
+			if (mouse.x > LeftPos.x - 30f && mouse.x < LeftPos.x + 10f && mouse.y > LeftPos.y - 30f && mouse.y < LeftPos.y + 30f)
+			{
+				Game.Scene.GetComponent<EventComponent>().Run(EventIdType.BehaviorTreeConnectState, this, State.ConnectLeft);
+			}
+
+			if (mouse.x > RightPos.x - 10f && mouse.x < RightPos.x + 30f && mouse.y > RightPos.y - 30f && mouse.y < RightPos.y + 30f && NodeData.CanAddChild())
+			{
+				Game.Scene.GetComponent<EventComponent>().Run(EventIdType.BehaviorTreeConnectState, this, State.ConnectRight);
+			}
+
+			for (int i = 0; i < this.Children.Count; i++)
+			{
+				this.Children[i].OnMousePos(mouse);
+			}
+		}
+
+		public void onSelect(bool flag)
+		{
+			isSelected = flag;
+			if (flag)
+			{
+				BTEntity.Instance.SelectNode(this.NodeData);
+			}
+		}
+
+		public void onDrag(Vector2 delta)
+		{
+			Offset = new Vector2(Offset.x + delta.x, Offset.y + delta.y);
+			Pos.x += delta.x;
+			Pos.y += delta.y;
+			UpdateChildrenPos(this.Offset);
+		}
+
+		//折叠
+		public void Fold()
+		{
+			DesignerData.fold = !DesignerData.fold;
+			UpdateChildren();
+		}
+
+		//自动排序
+		public void AutoSort()
+		{
+			this.Offset = Vector2.zero;
+			foreach (NodeDesigner child in this.Children)
+			{
+				child.AutoSort();
+			}
+			UpdateChildrenPos(this.Offset);
+		}
+
+		public bool FindChild(NodeDesigner dstNode)
+		{
+			if (this == dstNode)
+			{
+				return true;
+			}
+			foreach (NodeDesigner child in this.Children)
+			{
+				if (child.FindChild(dstNode))
+				{
+					return true;
+				}
+			}
+			return false;
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/NodeDesigner.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 9b9dab93ac8426c49abf1e0f3c557047
+timeCreated: 1445224516
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 290 - 0
Unity/Assets/Editor/BehaviorTreeEditor/NodeExtension.cs

@@ -0,0 +1,290 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using MyEditor;
+using UnityEditor;
+using UnityEngine;
+
+namespace Model
+{
+	public class BTEditorTree
+	{
+		private int _id = BTEntity.NodeIdStartIndex;
+		private readonly Node _root;
+
+		public BTEditorTree(BehaviorTreeConfig config)
+		{
+			Type rootType = typeof(Game).Assembly.GetType($"Model.{config.RootNodeProto.Name}");
+			Node root = (Node) Activator.CreateInstance(rootType, config.RootNodeProto);
+			root.Id = BTEntity.NodeIdStartIndex;
+			Queue<NodeProto> protoStack = new Queue<NodeProto>();
+			Queue<Node> nodeStack = new Queue<Node>();
+			protoStack.Enqueue(config.RootNodeProto);
+			nodeStack.Enqueue(root);
+			while (protoStack.Count > 0)
+			{
+				NodeProto p = protoStack.Dequeue();
+				Node node = nodeStack.Dequeue();
+
+				foreach (KeyValuePair<string, object> argsItem in p.Args.Dict())
+				{
+					FieldInfo fieldInfo = node.GetType().GetField(argsItem.Key, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
+					fieldInfo.SetValue(node, argsItem.Value);
+				}
+				foreach (NodeProto child in p.Children)
+				{
+					Type t = typeof(Game).Assembly.GetType($"Model.{child.Name}");
+					Node childNode = (Node) Activator.CreateInstance(t, child);
+					AddChild(childNode, node);
+					protoStack.Enqueue(child);
+					nodeStack.Enqueue(childNode);
+				}
+			}
+			this.BTConfig = config;
+			_root = root;
+		}
+
+		public T CreateNode<T>(Node parent) where T : Node
+		{
+			T node = (T) Activator.CreateInstance(typeof(T), new NodeProto());
+			AddChild(node, parent);
+			return node;
+		}
+
+		public string Description
+		{
+			get
+			{
+				return _root.Description;
+			}
+			set
+			{
+				_root.Description = value;
+			}
+		}
+
+		public BehaviorTreeConfig BTConfig { get; }
+
+		public T GetRoot<T>() where T : Node
+		{
+			return _root as T;
+		}
+
+		private BTEditorTree(Node root, BehaviorTreeConfig config)
+		{
+			_root = root;
+			_root.Id = BTEntity.NodeIdStartIndex;
+			this.BTConfig = config;
+		}
+
+		public static BTEditorTree CreateTree<T>(GameObject source)
+		{
+			BehaviorTreeConfig sourceTree = source.GetComponent<BehaviorTreeConfig>();
+			if (sourceTree == null)
+			{
+				sourceTree = source.AddComponent<BehaviorTreeConfig>();
+			}
+			Node root = (Node) Activator.CreateInstance(typeof(T), new NodeProto());
+			BTEditorTree tree = new BTEditorTree(root, sourceTree);
+			return tree;
+		}
+
+		public static BTEditorTree OpenFromGameObject(GameObject source)
+		{
+			BehaviorTreeConfig sourceTree = source.GetComponent<BehaviorTreeConfig>();
+			if (sourceTree == null)
+			{
+				throw new Exception($"{source.name}预制中不包含行为树");
+			}
+			return new BTEditorTree(sourceTree);
+		}
+
+		public T GetChildInType<T>() where T : Node
+		{
+			Queue<Node> nodeStack = new Queue<Node>();
+			nodeStack.Enqueue(_root);
+			while (nodeStack.Count > 0)
+			{
+				Node c = nodeStack.Dequeue();
+				if (c.GetType() == typeof(T))
+				{
+					return c as T;
+				}
+				foreach (Node child in c.GetChildren)
+				{
+					nodeStack.Enqueue(child);
+				}
+			}
+			return null;
+		}
+
+		public void AddChild(Node child, Node parent)
+		{
+			parent.AddChild(child);
+			child.Id = ++_id;
+		}
+
+		public T[] GetChildrenInType<T>() where T : Node
+		{
+			Queue<Node> nodeStack = new Queue<Node>();
+			List<T> list = new List<T>();
+			nodeStack.Enqueue(_root);
+			while (nodeStack.Count > 0)
+			{
+				Node c = nodeStack.Dequeue();
+				if (c.GetType() == typeof(T))
+				{
+					list.Add(c as T);
+				}
+				foreach (Node child in c.GetChildren)
+				{
+					nodeStack.Enqueue(child);
+				}
+			}
+			return list.ToArray();
+		}
+
+		public void SaveToBehaviorTreeConfig(BehaviorTreeConfig config)
+		{
+			_root.Serialize(config);
+		}
+
+		public void Save()
+		{
+			if (IsPrefab(this.BTConfig.gameObject))
+			{
+				GameObject go = UnityEngine.Object.Instantiate(this.BTConfig.gameObject);
+				go.name = this.BTConfig.gameObject.name;
+				BehaviorTreeConfig newConfig = go.GetComponent<BehaviorTreeConfig>();
+				_root.Serialize(newConfig);
+				PrefabUtility.ReplacePrefab(go, this.BTConfig, ReplacePrefabOptions.ReplaceNameBased);
+				UnityEngine.Object.DestroyImmediate(go);
+			}
+			else
+			{
+				_root.Serialize(this.BTConfig);
+			}
+		}
+
+		private bool IsPrefab(GameObject go)
+		{
+			string path = AssetDatabase.GetAssetPath(this.BTConfig);
+			return !string.IsNullOrEmpty(path);
+		}
+	}
+
+	public static class NodeExtension
+	{
+		public static T FindChildOnDesc<T>(this Node node, string desc) where T : Node
+		{
+			foreach (Node child in node.GetChildren)
+			{
+				if (child.Description == desc)
+				{
+					return node as T;
+				}
+			}
+			return null;
+		}
+
+		public static T GetChildInType<T>(this Node root) where T : Node
+		{
+			Queue<Node> nodeStack = new Queue<Node>();
+			nodeStack.Enqueue(root);
+			while (nodeStack.Count > 0)
+			{
+				Node c = nodeStack.Dequeue();
+				foreach (Node child in c.GetChildren)
+				{
+					if (child.GetType() == typeof(T))
+					{
+						return child as T;
+					}
+					nodeStack.Enqueue(child);
+				}
+			}
+			return null;
+		}
+
+		public static T[] GetChildrenInType<T>(this Node root) where T : Node
+		{
+			Queue<Node> nodeStack = new Queue<Node>();
+			List<T> list = new List<T>();
+			nodeStack.Enqueue(root);
+			while (nodeStack.Count > 0)
+			{
+				Node c = nodeStack.Dequeue();
+				foreach (Node child in c.GetChildren)
+				{
+					if (child.GetType() == typeof(T))
+					{
+						list.Add(child as T);
+					}
+					nodeStack.Enqueue(child);
+				}
+			}
+			return list.ToArray();
+		}
+
+		public static void Serialize(this Node root, BehaviorTreeConfig config)
+		{
+			config.Clear();
+			BehaviorNodeConfig rootNp = config.AddRootNode(root.GetType().Name);
+			Queue<Node> queue = new Queue<Node>();
+			Queue<BehaviorNodeConfig> npQue = new Queue<BehaviorNodeConfig>();
+			rootNp.describe = root.Description;
+			queue.Enqueue(root);
+			npQue.Enqueue(rootNp);
+			while (queue.Count > 0)
+			{
+				Node cur = queue.Dequeue();
+				BehaviorNodeConfig np = npQue.Dequeue();
+				foreach (Node child in cur.GetChildren)
+				{
+					BehaviorNodeConfig childNp = GetNodeConfigFromNode(child);
+					queue.Enqueue(child);
+					npQue.Enqueue(childNp);
+					config.AddChild(np, childNp);
+				}
+			}
+			//             PrintNode(root);
+			//             PrintConfigNode(config.RootNodeConfig);
+		}
+
+		//         private static void PrintNode(Node node)
+		//         {
+		//             Log.Info($"id:{node.Id}  type:{node.GetType().Name}");
+		//             foreach (var child in node.GetChildren)
+		//             {
+		//                 PrintNode(child);
+		//             }
+		//         }
+		//         private static void PrintConfigNode(BehaviorNodeConfig node)
+		//         {
+		//             Log.Info($"nodeConfigId:{node.id}  nodeConfigType:{node.name} childCount:{node.transform.childCount}");
+		//             foreach (Transform child in node.transform)
+		//             {
+		//                 PrintConfigNode(child.gameObject.GetComponent<BehaviorNodeConfig>());
+		//             }
+		//         }
+
+		private static NodeProto GetNodeProtoFromNode(Node node)
+		{
+			NodeProto np = new NodeProto();
+			np.Id = (int) node.Id;
+			FieldInfo[] mens = node.GetType().GetFields();
+			np.Desc = node.Description;
+			np.Name = node.GetType().Name;
+			foreach (FieldInfo men in mens)
+			{
+				np.Args.SetKeyValueComp(men.Name, men.GetValue(node));
+			}
+			return np;
+		}
+
+		private static BehaviorNodeConfig GetNodeConfigFromNode(Node node)
+		{
+			return BehaviorNodeConfigExtension.ProtoToConfig(GetNodeProtoFromNode(node));
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/NodeExtension.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 06fc66bf8a0291c4e89ef15ec6486f24
+timeCreated: 1474533109
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 37 - 0
Unity/Assets/Editor/BehaviorTreeEditor/NodeMeta.cs

@@ -0,0 +1,37 @@
+// 本文件由工具自动生成,请勿直接改动
+
+using System;
+using System.Collections.Generic;
+
+namespace Model
+{
+	public class NodeFieldDesc
+	{
+		public Type type;
+		public string name;
+		public object value;
+		public string desc;
+		public Type attributeType;
+		public Type[] constraintTypes;
+		public Type envKeyType;
+	}
+
+	public class NodeMeta
+	{
+		public string type = "";
+		public string name = "";
+		//public  string show_name = "";
+		public string describe = "";
+		public string classify = "";
+		public string style = "";
+		public int child_limit = 0;
+		public List<NodeFieldDesc> new_args_desc = new List<NodeFieldDesc>();
+		public bool isDeprecated;
+		public string deprecatedDesc;
+		
+		public override string ToString()
+		{
+			return $"Type:{type}, Desc:{describe}";
+		}
+	}
+}

+ 270 - 0
Unity/Assets/Editor/BehaviorTreeEditor/NodeMetaHelper.cs

@@ -0,0 +1,270 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using Model;
+using UnityEngine;
+using Object = UnityEngine.Object;
+
+namespace MyEditor
+{
+	public enum NodeChildLimitType
+	{
+		WithChild,
+		WithoutChild,
+		All
+	}
+
+	public static class NodeMetaHelper
+	{
+		public static Dictionary<NodeClassifyType, int> NodeTypeCountDict { get; } = new Dictionary<NodeClassifyType, int>
+		{
+			{ NodeClassifyType.Action, 0 },
+			{ NodeClassifyType.Composite, 999 },
+			{ NodeClassifyType.Condition, 0 },
+			{ NodeClassifyType.Decorator, 999 },
+			{ NodeClassifyType.Root, 999 },
+			{ NodeClassifyType.DataTransform, 0 }
+		};
+
+		public static Dictionary<string, NodeMeta> ExportToDict()
+		{
+			Dictionary<string, NodeMeta> name2NodeProtoDict = new Dictionary<string, NodeMeta>();
+			Type[] types = DllHelper.GetMonoTypes();
+			foreach (Type type in types)
+			{
+				NodeMeta proto = GetNodeTypeProtoFromType(type);
+				if (proto == null)
+				{
+					continue;
+				}
+				name2NodeProtoDict.Add(proto.name, proto);
+			}
+			return name2NodeProtoDict;
+		}
+
+		public static Assembly GetModelAssembly()
+		{
+			return typeof(Game).Assembly;
+		}
+
+		public static NodeMeta GetNodeTypeProtoFromType(Type type)
+		{
+			object[] nodeAttrs = type.GetCustomAttributes(typeof(NodeAttribute), false);
+			if (nodeAttrs.Length == 0)
+			{
+				return null;
+			}
+			object[] nodeDeprecatedAttrs = type.GetCustomAttributes(typeof(NodeDeprecatedAttribute), false);
+			NodeAttribute nodeAttribute = nodeAttrs[0] as NodeAttribute;
+			NodeDeprecatedAttribute nodeDeprecatedAttribute = null;
+			if (nodeDeprecatedAttrs.Length != 0)
+			{
+				nodeDeprecatedAttribute = nodeDeprecatedAttrs[0] as NodeDeprecatedAttribute;
+			}
+
+			NodeMeta proto = new NodeMeta()
+			{
+				type = nodeAttribute.ClassifytType.ToString(),
+				name = type.Name,
+				describe = nodeAttribute.Desc
+			};
+			if (nodeDeprecatedAttribute != null)
+			{
+				proto.isDeprecated = true;
+				proto.deprecatedDesc = nodeDeprecatedAttribute.Desc;
+			}
+
+			proto.new_args_desc.AddRange(GetNodeFieldDesc(type, typeof(NodeInputAttribute)));
+			proto.new_args_desc.AddRange(GetNodeFieldDesc(type, typeof(NodeOutputAttribute)));
+			proto.new_args_desc.AddRange(GetNodeFieldDesc(type, typeof(NodeFieldAttribute)));
+
+			proto.child_limit = NodeTypeCountDict[nodeAttribute.ClassifytType];
+			proto.classify = nodeAttribute.ClassifytType.ToString();
+			return proto;
+		}
+
+		public static List<NodeFieldDesc> GetNodeFieldInOutPutDescList(string nodeName, Type fieldAttributeType)
+		{
+			Type nodeType = GetNodeType(nodeName);
+			if (nodeType == null)
+			{
+				Log.Error($"{nodeName}节点不存在!!!");
+				return null;
+			}
+			return GetNodeFieldDesc(nodeType, fieldAttributeType);
+		}
+
+		public static List<NodeFieldDesc> GetNodeFieldInOutPutFilterDescList(string nodeName, Type fieldAttributeType, Type paramType)
+		{
+			List<NodeFieldDesc> list = GetNodeFieldInOutPutDescList(nodeName, fieldAttributeType);
+			List<NodeFieldDesc> filterList = new List<NodeFieldDesc>();
+			foreach (NodeFieldDesc item in list)
+			{
+				if (item.envKeyType == paramType || item.envKeyType.IsSubclassOf(paramType) || paramType.IsAssignableFrom(item.envKeyType))
+				{
+					filterList.Add(item);
+				}
+			}
+			return filterList;
+		}
+
+		public static List<NodeFieldDesc> GetNodeFieldDesc(Type type, Type fieldAttributeType)
+		{
+			List<NodeFieldDesc> list = new List<NodeFieldDesc>();
+			BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
+			FieldInfo[] fields = type.GetFields(flag);
+			foreach (FieldInfo field in fields)
+			{
+				object[] field_attrs = field.GetCustomAttributes(fieldAttributeType, false);
+				if (field_attrs.Length > 0)
+				{
+					NodeFieldBaseAttribute attri = field_attrs[0] as NodeFieldBaseAttribute;
+					NodeFieldDesc desc = new NodeFieldDesc();
+					desc.name = field.Name;
+					desc.desc = attri.Desc;
+					desc.type = field.FieldType;
+					desc.value = GetDefaultValue(field.FieldType, attri);
+					desc.attributeType = fieldAttributeType;
+					desc.envKeyType = attri.envKeyType;
+					if ((typeof(NodeInputAttribute) == fieldAttributeType || typeof(NodeInputAttribute) == fieldAttributeType) && desc.envKeyType == null)
+					{
+						Log.Error($"Node:{type.Name} Field:{desc.name}  _envKeyType can not be null");
+						return null;
+					}
+					object[] constraints = field.GetCustomAttributes(typeof(NodeFieldConstraintAttribute), false);
+					if (constraints.Length > 0)
+					{
+						NodeFieldConstraintAttribute constraint = constraints[0] as NodeFieldConstraintAttribute;
+						desc.constraintTypes = constraint.Types;
+					}
+
+					list.Add(desc);
+				}
+			}
+			return list;
+		}
+
+		public static object GetDefaultValue(Type type, NodeFieldBaseAttribute att)
+		{
+			if (att.DefaultValue != null)
+			{
+				if ((TypeHelper.IsEnumType(type) && BTEnvKey.None != att.DefaultValue.ToString()) || !TypeHelper.IsEnumType(type))
+				{
+					return att.DefaultValue;
+				}
+			}
+			object value = null;
+			if (TypeHelper.IsDoubleType(type))
+			{
+				value = default(double);
+			}
+			else if (TypeHelper.IsStringType(type))
+			{
+				value = default(string);
+			}
+			else if (TypeHelper.IsFloatType(type))
+			{
+				value = default(float);
+			}
+			else if (TypeHelper.IsBoolType(type))
+			{
+				value = default(bool);
+			}
+			else if (TypeHelper.IsIntType(type))
+			{
+				value = default(int);
+			}
+			else if (TypeHelper.IsLongType(type))
+			{
+				value = default(long);
+			}
+			else if (TypeHelper.IsIntArrType(type))
+			{
+				value = default(int[]);
+			}
+			else if (TypeHelper.IsLongArrType(type))
+			{
+				value = default(long[]);
+			}
+			else if (TypeHelper.IsDoubleArrType(type))
+			{
+				value = default(double[]);
+			}
+			else if (TypeHelper.IsFloatArrType(type))
+			{
+				value = default(float[]);
+			}
+			else if (TypeHelper.IsStringArrType(type))
+			{
+				value = default(string[]);
+			}
+			else if (TypeHelper.IsObjectType(type))
+			{
+				value = default(Object);
+			}
+			else if (TypeHelper.IsEnumType(type))
+			{
+				Array array = Enum.GetValues(type);
+				value = array.GetValue(0).ToString();
+			}
+			else if (TypeHelper.IsUnitConfigArrayType(type))
+			{
+			}
+			else if (TypeHelper.IsSpriteArrayType(type))
+			{
+				value = default(Sprite[]);
+			}
+			else if (TypeHelper.IsObjectArrayType(type))
+			{
+				value = default(Object[]);
+			}
+			else if (TypeHelper.IsConvertble(type))
+			{
+				value = 1f;
+			}
+			else
+			{
+				Log.Error($"行为树节点暂时未支持此类型:{type}!");
+				return null;
+			}
+			return value;
+		}
+
+		public static Type GetFieldType(string nodeName, string fieldName)
+		{
+			Type nodeType = GetNodeType(nodeName);
+			FieldInfo fieldInfo = nodeType.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
+			if (fieldInfo == null)
+			{
+				Log.Error($"{nodeName}节点不存在此属性:{fieldName}");
+			}
+			return fieldInfo.FieldType;
+		}
+
+		public static bool NodeHasField(string nodeName, string fieldName)
+		{
+			Type nodeType = GetNodeType(nodeName);
+			FieldInfo fieldInfo = nodeType.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
+			return fieldInfo != null;
+		}
+
+		public static FieldInfo[] GetFieldInfos(string nodeName)
+		{
+			Type nodeType = GetNodeType(nodeName);
+			FieldInfo[] fieldInfos = nodeType.GetFields();
+			return fieldInfos;
+		}
+
+		public static Type GetNodeType(string nodeName)
+		{
+			Assembly assembly = GetModelAssembly();
+			Type nodeType = assembly.GetType("Model." + nodeName);
+			if (nodeType == null)
+			{
+				Log.Error($"不存在此节点:{nodeName}");
+				return null;
+			}
+			return nodeType;
+		}
+	}
+}

+ 12 - 0
Unity/Assets/Editor/BehaviorTreeEditor/NodeMetaHelper.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 29b94d266875cf5408874b581cd9b12d
+timeCreated: 1448265008
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 9 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Pic.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 1313c2b359c675b4e88c8c4d38dc59b4
+folderAsset: yes
+timeCreated: 1486458634
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Unity/Assets/Editor/BehaviorTreeEditor/Pic/Bg.png


+ 56 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Pic/Bg.png.meta

@@ -0,0 +1,56 @@
+fileFormatVersion: 2
+guid: e32dde63ad92af041877969749ee8c63
+timeCreated: 1449654354
+licenseType: Pro
+TextureImporter:
+  fileIDToRecycleName: {}
+  serializedVersion: 2
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 1
+    linearTexture: 0
+    correctGamma: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: .25
+    normalMapFilter: 0
+  isReadable: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 0
+  cubemapConvolution: 0
+  cubemapConvolutionSteps: 8
+  cubemapConvolutionExponent: 1.5
+  seamlessCubemap: 0
+  textureFormat: -1
+  maxTextureSize: 2048
+  textureSettings:
+    filterMode: -1
+    aniso: -1
+    mipBias: -1
+    wrapMode: -1
+  nPOTScale: 1
+  lightmap: 0
+  rGBM: 0
+  compressionQuality: 50
+  allowsAlphaSplitting: 0
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: .5, y: .5}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  alphaIsTransparency: 0
+  textureType: -1
+  buildTargetSettings: []
+  spriteSheet:
+    sprites: []
+  spritePackingTag: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Unity/Assets/Editor/BehaviorTreeEditor/Pic/BgLine.png


+ 56 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Pic/BgLine.png.meta

@@ -0,0 +1,56 @@
+fileFormatVersion: 2
+guid: e8377c9eb02990742a168c9b3b910129
+timeCreated: 1449654318
+licenseType: Pro
+TextureImporter:
+  fileIDToRecycleName: {}
+  serializedVersion: 2
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 1
+    linearTexture: 0
+    correctGamma: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: .25
+    normalMapFilter: 0
+  isReadable: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 0
+  cubemapConvolution: 0
+  cubemapConvolutionSteps: 8
+  cubemapConvolutionExponent: 1.5
+  seamlessCubemap: 0
+  textureFormat: -1
+  maxTextureSize: 2048
+  textureSettings:
+    filterMode: -1
+    aniso: -1
+    mipBias: -1
+    wrapMode: -1
+  nPOTScale: 1
+  lightmap: 0
+  rGBM: 0
+  compressionQuality: 50
+  allowsAlphaSplitting: 0
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: .5, y: .5}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  alphaIsTransparency: 0
+  textureType: -1
+  buildTargetSettings: []
+  spriteSheet:
+    sprites: []
+  spritePackingTag: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Unity/Assets/Editor/BehaviorTreeEditor/Pic/DragIcon.png


+ 56 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Pic/DragIcon.png.meta

@@ -0,0 +1,56 @@
+fileFormatVersion: 2
+guid: efe6db2837926714eb5bcd0cb75cf145
+timeCreated: 1451531865
+licenseType: Pro
+TextureImporter:
+  fileIDToRecycleName: {}
+  serializedVersion: 2
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 1
+    linearTexture: 0
+    correctGamma: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: .25
+    normalMapFilter: 0
+  isReadable: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 0
+  cubemapConvolution: 0
+  cubemapConvolutionSteps: 8
+  cubemapConvolutionExponent: 1.5
+  seamlessCubemap: 0
+  textureFormat: -1
+  maxTextureSize: 2048
+  textureSettings:
+    filterMode: -1
+    aniso: -1
+    mipBias: -1
+    wrapMode: -1
+  nPOTScale: 1
+  lightmap: 0
+  rGBM: 0
+  compressionQuality: 50
+  allowsAlphaSplitting: 0
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: .5, y: .5}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  alphaIsTransparency: 0
+  textureType: -1
+  buildTargetSettings: []
+  spriteSheet:
+    sprites: []
+  spritePackingTag: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Unity/Assets/Editor/BehaviorTreeEditor/Pic/Error.png


+ 56 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Pic/Error.png.meta

@@ -0,0 +1,56 @@
+fileFormatVersion: 2
+guid: d60673d4340350b458ae68fb0289bf24
+timeCreated: 1450344240
+licenseType: Pro
+TextureImporter:
+  fileIDToRecycleName: {}
+  serializedVersion: 2
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 1
+    linearTexture: 0
+    correctGamma: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: .25
+    normalMapFilter: 0
+  isReadable: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 0
+  cubemapConvolution: 0
+  cubemapConvolutionSteps: 8
+  cubemapConvolutionExponent: 1.5
+  seamlessCubemap: 0
+  textureFormat: -1
+  maxTextureSize: 2048
+  textureSettings:
+    filterMode: -1
+    aniso: -1
+    mipBias: -1
+    wrapMode: -1
+  nPOTScale: 1
+  lightmap: 0
+  rGBM: 0
+  compressionQuality: 50
+  allowsAlphaSplitting: 0
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: .5, y: .5}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  alphaIsTransparency: 0
+  textureType: -1
+  buildTargetSettings: []
+  spriteSheet:
+    sprites: []
+  spritePackingTag: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Unity/Assets/Editor/BehaviorTreeEditor/Pic/Execute.png


+ 57 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Pic/Execute.png.meta

@@ -0,0 +1,57 @@
+fileFormatVersion: 2
+guid: 86520959e840cd74db5a81c9f8287fa9
+timeCreated: 1467167597
+licenseType: Pro
+TextureImporter:
+  fileIDToRecycleName: {}
+  serializedVersion: 2
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 1
+    linearTexture: 0
+    correctGamma: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: 0.25
+    normalMapFilter: 0
+  isReadable: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 0
+  cubemapConvolution: 0
+  cubemapConvolutionSteps: 7
+  cubemapConvolutionExponent: 1.5
+  seamlessCubemap: 0
+  textureFormat: -1
+  maxTextureSize: 2048
+  textureSettings:
+    filterMode: -1
+    aniso: -1
+    mipBias: -1
+    wrapMode: -1
+  nPOTScale: 1
+  lightmap: 0
+  rGBM: 0
+  compressionQuality: 50
+  allowsAlphaSplitting: 0
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: 0.5, y: 0.5}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  alphaIsTransparency: 0
+  textureType: -1
+  buildTargetSettings: []
+  spriteSheet:
+    sprites: []
+    outline: []
+  spritePackingTag: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Unity/Assets/Editor/BehaviorTreeEditor/Pic/False.png


+ 56 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Pic/False.png.meta

@@ -0,0 +1,56 @@
+fileFormatVersion: 2
+guid: 0e365bf6c03d807499f2e752286db1b0
+timeCreated: 1450085031
+licenseType: Pro
+TextureImporter:
+  fileIDToRecycleName: {}
+  serializedVersion: 2
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 1
+    linearTexture: 0
+    correctGamma: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: .25
+    normalMapFilter: 0
+  isReadable: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 0
+  cubemapConvolution: 0
+  cubemapConvolutionSteps: 8
+  cubemapConvolutionExponent: 1.5
+  seamlessCubemap: 0
+  textureFormat: -1
+  maxTextureSize: 2048
+  textureSettings:
+    filterMode: -1
+    aniso: -1
+    mipBias: -1
+    wrapMode: -1
+  nPOTScale: 1
+  lightmap: 0
+  rGBM: 0
+  compressionQuality: 50
+  allowsAlphaSplitting: 0
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: .5, y: .5}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  alphaIsTransparency: 0
+  textureType: -1
+  buildTargetSettings: []
+  spriteSheet:
+    sprites: []
+  spritePackingTag: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Unity/Assets/Editor/BehaviorTreeEditor/Pic/HighLight.png


+ 56 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Pic/HighLight.png.meta

@@ -0,0 +1,56 @@
+fileFormatVersion: 2
+guid: 468d8ad9125387641bf8844cff5912b5
+timeCreated: 1449811576
+licenseType: Pro
+TextureImporter:
+  fileIDToRecycleName: {}
+  serializedVersion: 2
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 1
+    linearTexture: 0
+    correctGamma: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: .25
+    normalMapFilter: 0
+  isReadable: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 0
+  cubemapConvolution: 0
+  cubemapConvolutionSteps: 8
+  cubemapConvolutionExponent: 1.5
+  seamlessCubemap: 0
+  textureFormat: -1
+  maxTextureSize: 2048
+  textureSettings:
+    filterMode: -1
+    aniso: -1
+    mipBias: -1
+    wrapMode: -1
+  nPOTScale: 1
+  lightmap: 0
+  rGBM: 0
+  compressionQuality: 50
+  allowsAlphaSplitting: 0
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: .5, y: .5}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  alphaIsTransparency: 0
+  textureType: -1
+  buildTargetSettings: []
+  spriteSheet:
+    sprites: []
+  spritePackingTag: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Unity/Assets/Editor/BehaviorTreeEditor/Pic/LeftConnect.png


+ 56 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Pic/LeftConnect.png.meta

@@ -0,0 +1,56 @@
+fileFormatVersion: 2
+guid: 9eadb585690aeef4fa4c051dc7d26cfd
+timeCreated: 1450060197
+licenseType: Pro
+TextureImporter:
+  fileIDToRecycleName: {}
+  serializedVersion: 2
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 1
+    linearTexture: 0
+    correctGamma: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: .25
+    normalMapFilter: 0
+  isReadable: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 0
+  cubemapConvolution: 0
+  cubemapConvolutionSteps: 8
+  cubemapConvolutionExponent: 1.5
+  seamlessCubemap: 0
+  textureFormat: -1
+  maxTextureSize: 2048
+  textureSettings:
+    filterMode: -1
+    aniso: -1
+    mipBias: -1
+    wrapMode: -1
+  nPOTScale: 1
+  lightmap: 0
+  rGBM: 0
+  compressionQuality: 50
+  allowsAlphaSplitting: 0
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: .5, y: .5}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  alphaIsTransparency: 0
+  textureType: -1
+  buildTargetSettings: []
+  spriteSheet:
+    sprites: []
+  spritePackingTag: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Unity/Assets/Editor/BehaviorTreeEditor/Pic/RightConnect.png


+ 56 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Pic/RightConnect.png.meta

@@ -0,0 +1,56 @@
+fileFormatVersion: 2
+guid: f81309799121cb344abab8c27226923a
+timeCreated: 1450060197
+licenseType: Pro
+TextureImporter:
+  fileIDToRecycleName: {}
+  serializedVersion: 2
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 1
+    linearTexture: 0
+    correctGamma: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: .25
+    normalMapFilter: 0
+  isReadable: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 0
+  cubemapConvolution: 0
+  cubemapConvolutionSteps: 8
+  cubemapConvolutionExponent: 1.5
+  seamlessCubemap: 0
+  textureFormat: -1
+  maxTextureSize: 2048
+  textureSettings:
+    filterMode: -1
+    aniso: -1
+    mipBias: -1
+    wrapMode: -1
+  nPOTScale: 1
+  lightmap: 0
+  rGBM: 0
+  compressionQuality: 50
+  allowsAlphaSplitting: 0
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: .5, y: .5}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  alphaIsTransparency: 0
+  textureType: -1
+  buildTargetSettings: []
+  spriteSheet:
+    sprites: []
+  spritePackingTag: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Unity/Assets/Editor/BehaviorTreeEditor/Pic/SelectHighLight.png


+ 56 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Pic/SelectHighLight.png.meta

@@ -0,0 +1,56 @@
+fileFormatVersion: 2
+guid: 1222e9b63c7117c47bf9ec8b5f347dfd
+timeCreated: 1450064233
+licenseType: Pro
+TextureImporter:
+  fileIDToRecycleName: {}
+  serializedVersion: 2
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 1
+    linearTexture: 0
+    correctGamma: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: .25
+    normalMapFilter: 0
+  isReadable: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 0
+  cubemapConvolution: 0
+  cubemapConvolutionSteps: 8
+  cubemapConvolutionExponent: 1.5
+  seamlessCubemap: 0
+  textureFormat: -1
+  maxTextureSize: 2048
+  textureSettings:
+    filterMode: -1
+    aniso: -1
+    mipBias: -1
+    wrapMode: -1
+  nPOTScale: 1
+  lightmap: 0
+  rGBM: 0
+  compressionQuality: 50
+  allowsAlphaSplitting: 0
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: .5, y: .5}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  alphaIsTransparency: 0
+  textureType: -1
+  buildTargetSettings: []
+  spriteSheet:
+    sprites: []
+  spritePackingTag: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Unity/Assets/Editor/BehaviorTreeEditor/Pic/ShiftIcon.png


+ 56 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Pic/ShiftIcon.png.meta

@@ -0,0 +1,56 @@
+fileFormatVersion: 2
+guid: 0744818daf7d82d45b534869e9746462
+timeCreated: 1451531865
+licenseType: Pro
+TextureImporter:
+  fileIDToRecycleName: {}
+  serializedVersion: 2
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 1
+    linearTexture: 0
+    correctGamma: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: .25
+    normalMapFilter: 0
+  isReadable: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 0
+  cubemapConvolution: 0
+  cubemapConvolutionSteps: 8
+  cubemapConvolutionExponent: 1.5
+  seamlessCubemap: 0
+  textureFormat: -1
+  maxTextureSize: 2048
+  textureSettings:
+    filterMode: -1
+    aniso: -1
+    mipBias: -1
+    wrapMode: -1
+  nPOTScale: 1
+  lightmap: 0
+  rGBM: 0
+  compressionQuality: 50
+  allowsAlphaSplitting: 0
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: .5, y: .5}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  alphaIsTransparency: 0
+  textureType: -1
+  buildTargetSettings: []
+  spriteSheet:
+    sprites: []
+  spritePackingTag: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Unity/Assets/Editor/BehaviorTreeEditor/Pic/True.png


+ 56 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Pic/True.png.meta

@@ -0,0 +1,56 @@
+fileFormatVersion: 2
+guid: e7ccf46f66171bb4491c1f77d88b7858
+timeCreated: 1450082734
+licenseType: Pro
+TextureImporter:
+  fileIDToRecycleName: {}
+  serializedVersion: 2
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 1
+    linearTexture: 0
+    correctGamma: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: .25
+    normalMapFilter: 0
+  isReadable: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 0
+  cubemapConvolution: 0
+  cubemapConvolutionSteps: 8
+  cubemapConvolutionExponent: 1.5
+  seamlessCubemap: 0
+  textureFormat: -1
+  maxTextureSize: 2048
+  textureSettings:
+    filterMode: -1
+    aniso: -1
+    mipBias: -1
+    wrapMode: -1
+  nPOTScale: 1
+  lightmap: 0
+  rGBM: 0
+  compressionQuality: 50
+  allowsAlphaSplitting: 0
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: .5, y: .5}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  alphaIsTransparency: 0
+  textureType: -1
+  buildTargetSettings: []
+  spriteSheet:
+    sprites: []
+  spritePackingTag: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Unity/Assets/Editor/BehaviorTreeEditor/Pic/blue.png


+ 56 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Pic/blue.png.meta

@@ -0,0 +1,56 @@
+fileFormatVersion: 2
+guid: ac809af2a0ce2d1489b5db1d8b668f61
+timeCreated: 1449731762
+licenseType: Pro
+TextureImporter:
+  fileIDToRecycleName: {}
+  serializedVersion: 2
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 1
+    linearTexture: 0
+    correctGamma: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: .25
+    normalMapFilter: 0
+  isReadable: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 0
+  cubemapConvolution: 0
+  cubemapConvolutionSteps: 8
+  cubemapConvolutionExponent: 1.5
+  seamlessCubemap: 0
+  textureFormat: -1
+  maxTextureSize: 2048
+  textureSettings:
+    filterMode: -1
+    aniso: -1
+    mipBias: -1
+    wrapMode: -1
+  nPOTScale: 1
+  lightmap: 0
+  rGBM: 0
+  compressionQuality: 50
+  allowsAlphaSplitting: 0
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: .5, y: .5}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  alphaIsTransparency: 0
+  textureType: -1
+  buildTargetSettings: []
+  spriteSheet:
+    sprites: []
+  spritePackingTag: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Unity/Assets/Editor/BehaviorTreeEditor/Pic/default.png


+ 56 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Pic/default.png.meta

@@ -0,0 +1,56 @@
+fileFormatVersion: 2
+guid: b21f78cb47cab8a409bbe7c7331f8be7
+timeCreated: 1449731945
+licenseType: Pro
+TextureImporter:
+  fileIDToRecycleName: {}
+  serializedVersion: 2
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 1
+    linearTexture: 0
+    correctGamma: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: .25
+    normalMapFilter: 0
+  isReadable: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 0
+  cubemapConvolution: 0
+  cubemapConvolutionSteps: 8
+  cubemapConvolutionExponent: 1.5
+  seamlessCubemap: 0
+  textureFormat: -1
+  maxTextureSize: 2048
+  textureSettings:
+    filterMode: -1
+    aniso: -1
+    mipBias: -1
+    wrapMode: -1
+  nPOTScale: 1
+  lightmap: 0
+  rGBM: 0
+  compressionQuality: 50
+  allowsAlphaSplitting: 0
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: .5, y: .5}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  alphaIsTransparency: 0
+  textureType: -1
+  buildTargetSettings: []
+  spriteSheet:
+    sprites: []
+  spritePackingTag: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Unity/Assets/Editor/BehaviorTreeEditor/Pic/green.png


+ 56 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Pic/green.png.meta

@@ -0,0 +1,56 @@
+fileFormatVersion: 2
+guid: a82cc1b059d7d0b4681eda29d2bce920
+timeCreated: 1449731762
+licenseType: Pro
+TextureImporter:
+  fileIDToRecycleName: {}
+  serializedVersion: 2
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 1
+    linearTexture: 0
+    correctGamma: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: .25
+    normalMapFilter: 0
+  isReadable: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 0
+  cubemapConvolution: 0
+  cubemapConvolutionSteps: 8
+  cubemapConvolutionExponent: 1.5
+  seamlessCubemap: 0
+  textureFormat: -1
+  maxTextureSize: 2048
+  textureSettings:
+    filterMode: -1
+    aniso: -1
+    mipBias: -1
+    wrapMode: -1
+  nPOTScale: 1
+  lightmap: 0
+  rGBM: 0
+  compressionQuality: 50
+  allowsAlphaSplitting: 0
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: .5, y: .5}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  alphaIsTransparency: 0
+  textureType: -1
+  buildTargetSettings: []
+  spriteSheet:
+    sprites: []
+  spritePackingTag: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Unity/Assets/Editor/BehaviorTreeEditor/Pic/orange.png


+ 56 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Pic/orange.png.meta

@@ -0,0 +1,56 @@
+fileFormatVersion: 2
+guid: 1027c8091bd4a41419f3be5a4bf5d137
+timeCreated: 1449731762
+licenseType: Pro
+TextureImporter:
+  fileIDToRecycleName: {}
+  serializedVersion: 2
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 1
+    linearTexture: 0
+    correctGamma: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: .25
+    normalMapFilter: 0
+  isReadable: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 0
+  cubemapConvolution: 0
+  cubemapConvolutionSteps: 8
+  cubemapConvolutionExponent: 1.5
+  seamlessCubemap: 0
+  textureFormat: -1
+  maxTextureSize: 2048
+  textureSettings:
+    filterMode: -1
+    aniso: -1
+    mipBias: -1
+    wrapMode: -1
+  nPOTScale: 1
+  lightmap: 0
+  rGBM: 0
+  compressionQuality: 50
+  allowsAlphaSplitting: 0
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: .5, y: .5}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  alphaIsTransparency: 0
+  textureType: -1
+  buildTargetSettings: []
+  spriteSheet:
+    sprites: []
+  spritePackingTag: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Unity/Assets/Editor/BehaviorTreeEditor/Pic/pink.png


+ 56 - 0
Unity/Assets/Editor/BehaviorTreeEditor/Pic/pink.png.meta

@@ -0,0 +1,56 @@
+fileFormatVersion: 2
+guid: 768f477264f644640a5ab31678f4d92f
+timeCreated: 1449731762
+licenseType: Pro
+TextureImporter:
+  fileIDToRecycleName: {}
+  serializedVersion: 2
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 1
+    linearTexture: 0
+    correctGamma: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: .25
+    normalMapFilter: 0
+  isReadable: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 0
+  cubemapConvolution: 0
+  cubemapConvolutionSteps: 8
+  cubemapConvolutionExponent: 1.5
+  seamlessCubemap: 0
+  textureFormat: -1
+  maxTextureSize: 2048
+  textureSettings:
+    filterMode: -1
+    aniso: -1
+    mipBias: -1
+    wrapMode: -1
+  nPOTScale: 1
+  lightmap: 0
+  rGBM: 0
+  compressionQuality: 50
+  allowsAlphaSplitting: 0
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: .5, y: .5}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  alphaIsTransparency: 0
+  textureType: -1
+  buildTargetSettings: []
+  spriteSheet:
+    sprites: []
+  spritePackingTag: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

Некоторые файлы не были показаны из-за большого количества измененных файлов