public ConnectionLineView(PortEditorView portViewA, PortEditorView portViewB, GraphEditorData graphEditorData) { if (portViewA.FlowType == portViewB.FlowType) { Debug.LogError("两个端口的FlowType相同,无法连接"); return; } this.graphEditorData = graphEditorData; this.FlowOutPortView = portViewA.FlowType == FlowType.In ? portViewB : portViewA; this.FlowInPortView = portViewB.FlowType == FlowType.In ? portViewB : portViewA; //流入节点都只允许一个连接 graphEditorData.ClearPortAllConnections(FlowInPortView); if (!FlowOutPortView.connectedPortList.Contains(FlowInPortView)) { FlowOutPortView.connectedPortList.Add(FlowInPortView); } if (!FlowInPortView.connectedPortList.Contains(FlowOutPortView)) { FlowInPortView.connectedPortList.Add(FlowOutPortView); } }
/// <summary> /// 载入完成时,如果是<see cref="GetVariableNode"/>或者<see cref="SetVariableNode"/> 则需要初始化更新对应端口的类型 /// </summary> public override void OnLoadFinish() { base.OnLoadFinish(); //初始化读写节点的端口类型 //如果input port端口的类型是VariableWrapper,则看是否设置的有值,有值的话更新整个端口的类型 VariableWrapper variableWrapper = inputPortReflectionInfo.GetInputNodeVariableValue() as VariableWrapper; if (variableWrapper == null) { return; } int variableId = variableWrapper.variableId; GraphEditorData data = NodeView.graph.data; GraphVariableInfo graphVariableInfo = data.GetGraphVariableInfo(variableId); if (graphVariableInfo != null) { NodeView.UpdateGraphVariableNodeIOPortType(graphVariableInfo.valueType, true); } else { NodeView.UpdateGraphVariableNodeIOPortType(null, true); } }
private static void AddOrUpdateGraphsRecord(GraphEditorData data) { if (File.Exists(GraphRecordFilePath)) { string jsonString = File.ReadAllText(GraphRecordFilePath); GraphRecord graphRecord = new GraphRecord(); EditorJsonUtility.FromJsonOverwrite(jsonString, graphRecord); bool hasFoundGraph = false; for (int i = 0; i < graphRecord.graphBaseInfoList.Count; i++) { if (graphRecord.graphBaseInfoList[i].graphId == data.graphId) { hasFoundGraph = true; graphRecord.graphBaseInfoList[i].graphName = data.graphName; graphRecord.graphBaseInfoList[i].graphDescription = data.graphDescription; break; } } if (!hasFoundGraph) { graphRecord.graphBaseInfoList.Add(new GraphBaseInfo { graphId = data.graphId, graphName = data.graphName, graphDescription = data.graphDescription }); graphRecord.nextGraphId++; } jsonString = EditorJsonUtility.ToJson(graphRecord, true); File.WriteAllText(GraphRecordFilePath, jsonString); } else { GraphRecord graphRecord = new GraphRecord(); graphRecord.graphBaseInfoList = new List <GraphBaseInfo>(); graphRecord.graphBaseInfoList.Add(new GraphBaseInfo() { graphId = data.graphId, graphName = data.graphName, graphDescription = data.graphDescription }); graphRecord.nextGraphId++; string jsonString = EditorJsonUtility.ToJson(graphRecord, true); File.WriteAllText(GraphRecordFilePath, jsonString); } AssetDatabase.Refresh(); }
void OpenGraphLoadWindow(object mousePositionObject) { Vector2 mousePosition = (Vector2)mousePositionObject; try { PopupWindow.Show(new Rect(mousePosition + position.position, new Vector2(500, 0)), new LoadGraphPopupWindow( loadGraphId => { Reset(); data = PersistenceTool.LoadGraph(this, loadGraphId); //做一些载入完成的初始化工作 data.OnLoadFinish(); //检查连线的合法性 data.CheckAllNodeConnection(); })); } catch { } }
private void OnGUI() { instance = this; //初始化 if (supportTypeNames == null) { supportTypeNames = new string[supportTypeList.Count]; for (int i = 0; i < supportTypeList.Count; i++) { supportTypeNames[i] = Utility.BeautifyTypeName(supportTypeList[i]); } } //draw title GUILayout.Label("行为图属性", Utility.GetGuiStyle("Title")); GUILayout.Space(10); GraphEditorWindow graphEditorWindow = GraphEditorWindow.instance; if (graphEditorWindow == null || graphEditorWindow.data == null) { GUILayout.Label("请先打开行为图编辑器窗口", Utility.GetGuiStyle("SkillGraphName")); return; } data = graphEditorWindow.data; DrawToolButtons(); GUILayout.Space(30); DrawLocalVariableItemList(); }
private void OnEnable() { instance = this; data = new GraphEditorData(); Reset(); }
private static void UpdateNodeViewData(NodeConfigInfo nodeConfigInfo, NodeEditorView nodeView, GraphEditorData data) { //flow in port--处理流出节点的时候顺便就处理了 //flow out port for (int i = 0; i < nodeConfigInfo.flowOutPortInfoList.Count; i++) { FlowOutPortConfigInfo flowOutPortConfigInfo = nodeConfigInfo.flowOutPortInfoList[i]; FlowOutPortEditorView flowOutPortView = GetFlowOutPortViewByPortName(nodeView.flowOutPortViews, flowOutPortConfigInfo.flowOutPortName); if (flowOutPortView == null) { Debug.LogFormat("节点{0}中找不到流出端口 <{1}> 了,该端口的连接被忽略", nodeView.ReflectionInfo.Type, flowOutPortConfigInfo.flowOutPortName); continue; } for (int j = 0; j < flowOutPortConfigInfo.targetNodeList.Count; j++) { int targetNodeId = flowOutPortConfigInfo.targetNodeList[j]; NodeEditorView targetNodeView = data.GetNode(targetNodeId); if (targetNodeView == null) { Debug.LogErrorFormat("无法找到节点{0},可能是配置损坏/更改了类名...", targetNodeId); continue; } if (targetNodeView.flowInPortView == null) { Debug.LogErrorFormat("节点类型{0}没有流入节点,是否节点性质发生了改变?", nodeView.ReflectionInfo.Type.FullName); continue; } ConnectionLineView connectionLineView = new ConnectionLineView(flowOutPortView, targetNodeView.flowInPortView, data); data.connectionLineList.Add(connectionLineView); } } //output port -- 不用配置 //input port for (int i = 0; i < nodeConfigInfo.inputPortInfoList.Count; i++) { InputPortConfigInfo inputPortConfigInfo = nodeConfigInfo.inputPortInfoList[i]; InputPortEditorView inputPortView = GetInputPortViewByPortName(nodeView.inputPortViewList, inputPortConfigInfo.portName); if (inputPortView == null) { Debug.LogFormat("节点{0}中无法找到接口名字为 <{1}> 的NodeInputVariable Field,该接口配置被跳过", nodeView.ReflectionInfo.Type.FullName, inputPortConfigInfo.portName); continue; } //没有连接到其他节点的情况 if (string.IsNullOrEmpty(inputPortConfigInfo.targetPortName)) { //设置默认值 Type valueType = Type.GetType(inputPortConfigInfo.nodeVariableGenericTypeName); if (valueType == null) { valueType = Type.GetType(inputPortConfigInfo.nodeVariableGenericTypeName + ",UnityEngine"); if (valueType == null) { valueType = Type.GetType(inputPortConfigInfo.nodeVariableGenericTypeName + ",Assembly-CSharp"); } } if (valueType == null) { Debug.LogErrorFormat("工程中找不到类型: {0}", inputPortConfigInfo.nodeVariableGenericTypeName); continue; } SetNodeInputVariableValue(inputPortView.inputPortReflectionInfo, valueType, inputPortConfigInfo.nodeVariableValue, nodeView); } //连接到其他节点的情况 else { NodeEditorView connectedToNodeView = data.GetNode(inputPortConfigInfo.targetNodeId); if (connectedToNodeView == null) { Debug.LogErrorFormat("节点 {0} 的input接口 {1} 找不到连接的节点{2}", nodeView.NodeId, inputPortConfigInfo.portName, inputPortConfigInfo.targetNodeId); continue; } OutputPortEditorView connectedToOutputPortView = GetOutputPortViewByPortName(connectedToNodeView.outputPortViewList, inputPortConfigInfo.targetPortName); if (connectedToOutputPortView == null) { Debug.LogFormat("找不到节点{0}中 接口名字为 <{1}> 的output接口,该接口的连接被跳过", connectedToNodeView.NodeId, inputPortConfigInfo.targetPortName); continue; } ConnectionLineView connectionLineView = new ConnectionLineView(inputPortView, connectedToOutputPortView, data); data.connectionLineList.Add(connectionLineView); } } }
public static GraphEditorData LoadGraph(GraphEditorWindow graph, int graphId) { GraphEditorData resultData = new GraphEditorData(); string graphEditorConfigFilePath = Path.Combine(Application.dataPath, string.Format("FlatNode/Editor/GraphSavedConfig/{0}.json", graphId)); if (!File.Exists(graphEditorConfigFilePath)) { Debug.LogErrorFormat("无法载入行为图配置文件: {0}", graphEditorConfigFilePath); } string jsonString = File.ReadAllText(graphEditorConfigFilePath); GraphConfigInfo graphConfigInfo = new GraphConfigInfo(); EditorJsonUtility.FromJsonOverwrite(jsonString, graphConfigInfo); //处理注释框 for (int i = 0; i < graphConfigInfo.commentBoxInfoList.Count; i++) { CommentBoxInfo commentBoxInfo = graphConfigInfo.commentBoxInfoList[i]; CommentBoxView commentBoxView = ParseCommentBoxInfo(commentBoxInfo, graph); resultData.commentBoxViewList.Add(commentBoxView); } //变量 for (int i = 0; i < graphConfigInfo.graphVariableInfoList.Count; i++) { if (!graphConfigInfo.graphVariableInfoList[i].Validate()) { continue; } resultData.graphVariableInfoList.Add(graphConfigInfo.graphVariableInfoList[i].OnDeserialized()); } //如果有节点无法解析出来(可能是改了类名称之类的),则需要跳过这些节点 HashSet <int> errorNodeIndexSet = new HashSet <int>(); //首先将所有的节点都生成 for (int i = 0; i < graphConfigInfo.nodesList.Count; i++) { NodeEditorView nodeView = ParseNodeInfo(graphConfigInfo.nodesList[i], graph); if (nodeView == null) { errorNodeIndexSet.Add(i); continue; } resultData.nodeList.Add(nodeView); } //然后再将所有节点的内容写进去,将节点连起来 int nodeIndex = 0; for (int i = 0; i < graphConfigInfo.nodesList.Count; i++) { if (errorNodeIndexSet.Contains(i)) { //skip continue; } UpdateNodeViewData(graphConfigInfo.nodesList[i], resultData.nodeList[nodeIndex], resultData); nodeIndex++; } resultData.graphId = graphConfigInfo.graphId; resultData.graphName = graphConfigInfo.graphName; resultData.graphDescription = graphConfigInfo.graphDescription; return(resultData); }
public static void SaveGraph(GraphEditorData data) { string jsonString = String.Empty; byte[] runtimeConfigBytes = null; bool isSuccess = true; try { //存储技能配置json文件,配置文件使用json是因为可读性好 GraphConfigInfo graphConfigInfo = new GraphConfigInfo { graphId = data.graphId, graphName = data.graphName, graphDescription = data.graphDescription, nodesList = new List <NodeConfigInfo>(), commentBoxInfoList = new List <CommentBoxInfo>(), graphVariableInfoList = new List <GraphVariableInfo>(), }; for (int i = 0; i < data.nodeList.Count; i++) { NodeEditorView nodeView = data.nodeList[i]; graphConfigInfo.nodesList.Add(ConvertToNodeInfo(nodeView)); } for (int i = 0; i < data.commentBoxViewList.Count; i++) { CommentBoxView commentBoxView = data.commentBoxViewList[i]; graphConfigInfo.commentBoxInfoList.Add(ConvertToCommentInfo(commentBoxView)); } for (int i = 0; i < data.graphVariableInfoList.Count; i++) { graphConfigInfo.graphVariableInfoList.Add(data.graphVariableInfoList[i].OnSerialized()); } jsonString = JsonUtility.ToJson(graphConfigInfo, true); runtimeConfigBytes = ConvertToRuntimeInfo(data.nodeList, data.graphVariableInfoList, data.graphId); } catch (Exception e) { isSuccess = false; Debug.LogError(e.Message); throw; } finally { if (isSuccess) { string graphEditorConfigFilePath = Path.Combine(Application.dataPath, string.Format("FlatNode/Editor/GraphSavedConfig/{0}.json", data.graphId)); File.WriteAllText(graphEditorConfigFilePath, jsonString); string graphRuntimeConfigFilePath = Path.Combine(Application.dataPath, string.Format("Resources/GraphRuntime/{0}.bytes", data.graphId)); string parentDirctoryPath = Directory.GetParent(graphRuntimeConfigFilePath).FullName; if (!Directory.Exists(parentDirctoryPath)) { Directory.CreateDirectory(parentDirctoryPath); } if (runtimeConfigBytes != null) { File.WriteAllBytes(graphRuntimeConfigFilePath, runtimeConfigBytes); } //更新所有图的记录文件 AddOrUpdateGraphsRecord(data); AssetDatabase.Refresh(); } } }
/// <summary> /// 绘制各种类型的输入框 /// </summary> /// <param name="type"></param> void DrawInputFieldLabel(Type type) { if (type == typeof(float)) { string typeName = Utility.BeautifyTypeName(type) + ": "; CalculateAndDrawLabelCommonElement(typeName, 100f); EditorGUI.BeginChangeCheck(); float value = (float)inputPortReflectionInfo.GetInputNodeVariableValue(); value = EditorGUI.FloatField(labelInputAreaRect, value); if (EditorGUI.EndChangeCheck()) { inputPortReflectionInfo.SetInputNodeVariableValue(value); } } else if (type == typeof(int)) { string typeName = Utility.BeautifyTypeName(type) + ": "; CalculateAndDrawLabelCommonElement(typeName, 100f); EditorGUI.BeginChangeCheck(); int value = (int)inputPortReflectionInfo.GetInputNodeVariableValue(); value = EditorGUI.IntField(labelInputAreaRect, value); if (EditorGUI.EndChangeCheck()) { inputPortReflectionInfo.SetInputNodeVariableValue(value); } } else if (type == typeof(string)) { string typeName = Utility.BeautifyTypeName(type) + ": "; CalculateAndDrawLabelCommonElement(typeName, 100f); EditorGUI.BeginChangeCheck(); string value = (string)inputPortReflectionInfo.GetInputNodeVariableValue(); if (GUI.Button(labelInputAreaRect, value)) { PopupWindow.Show(labelInputAreaRect, new StringEditPopupWindow(value, stringContent => { inputPortReflectionInfo.SetInputNodeVariableValue(stringContent); })); } } else if (type == typeof(bool)) { string typeName = Utility.BeautifyTypeName(type) + ": "; CalculateAndDrawLabelCommonElement(typeName, 20f); EditorGUI.BeginChangeCheck(); bool value = (bool)inputPortReflectionInfo.GetInputNodeVariableValue(); value = EditorGUI.Toggle(labelInputAreaRect, value); if (EditorGUI.EndChangeCheck()) { inputPortReflectionInfo.SetInputNodeVariableValue(value); } } else if (type.IsEnum) { if (maxEnumNeedWidth < 0) { maxEnumNeedWidth = Utility.GetEnumMaxGuiWidth(type, 16); } string typeName = Utility.BeautifyTypeName(type) + ": "; CalculateAndDrawLabelCommonElement(typeName, maxEnumNeedWidth + 25); //25是enum选择框箭头的位置 EditorGUI.BeginChangeCheck(); Enum enumValue = (Enum)inputPortReflectionInfo.GetInputNodeVariableValue(); enumValue = EditorGUI.EnumPopup(labelInputAreaRect, enumValue); if (EditorGUI.EndChangeCheck()) { inputPortReflectionInfo.SetInputNodeVariableValue(enumValue); } } //支持list<int> else if (type == typeof(List <int>)) { string typeName = Utility.BeautifyTypeName(type) + ": "; CalculateAndDrawLabelCommonElement(typeName, 100f); List <int> list = inputPortReflectionInfo.GetInputNodeVariableValue() as List <int>; if (list == null) { list = new List <int>(); } string listHint = string.Join(",", list.Select(x => x.ToString()).ToArray()); if (GUI.Button(labelInputAreaRect, listHint)) { ListIntEditorWindow.ShowWindow(list, editedList => { inputPortReflectionInfo.SetInputNodeVariableValue(editedList); }); } } else if (type == typeof(LayerMaskWrapper)) { if (maxLayerMaskNeedWidth < 0) { maxLayerMaskNeedWidth = Utility.GetLayerMaxGuiLength(8); } string typeName = Utility.BeautifyTypeName(type) + ": "; CalculateAndDrawLabelCommonElement(typeName, maxLayerMaskNeedWidth + 25); EditorGUI.BeginChangeCheck(); LayerMaskWrapper layerMaskWrapperValue = (LayerMaskWrapper)inputPortReflectionInfo.GetInputNodeVariableValue(); if (layerMaskWrapperValue == null) { layerMaskWrapperValue = new LayerMaskWrapper(); } string[] gameLayerNames = Utility.GetUnityLayerNames(); int selectLayer = EditorGUI.MaskField(labelInputAreaRect, layerMaskWrapperValue.layer, gameLayerNames); if (EditorGUI.EndChangeCheck()) { layerMaskWrapperValue.layer = selectLayer; // Debug.Log("select layer mask: " + layerMaskValue); inputPortReflectionInfo.SetInputNodeVariableValue(layerMaskWrapperValue); } } //选择技能变量 else if (type == typeof(VariableWrapper)) { VariableWrapper variableWrapper = inputPortReflectionInfo.GetInputNodeVariableValue() as VariableWrapper; if (variableWrapper == null) { variableWrapper = new VariableWrapper(); } int varibleId = variableWrapper.variableId; GraphEditorData data = GraphEditorWindow.instance.data; GraphVariableInfo graphVariableInfo = data.GetGraphVariableInfo(varibleId); string buttonName; //当前没有选择任何一个变量 if (graphVariableInfo == null) { buttonName = "选择一个变量!"; } else { buttonName = graphVariableInfo.name; } CalculateAndDrawLabelCommonElement("变量: ", EditorStyles.label.CalcSize(new GUIContent(buttonName)).x + 20); if (GUI.Button(labelInputAreaRect, buttonName)) { PopupWindow.Show(labelInputAreaRect, new SelectGraphVariablePopupWindow(data.CurrentGraphVariableInfoList, selectVariableId => { variableWrapper.variableId = selectVariableId; inputPortReflectionInfo.SetInputNodeVariableValue(variableWrapper); Type variableType = GraphEditorWindow.instance.data .GetGraphVariableInfo(selectVariableId).valueType; NodeView.UpdateGraphVariableNodeIOPortType(variableType, true); })); } } //所有需要自定义Input标签的类型写在这个分支前面 else if (type.IsClass) { string typeName = Utility.BeautifyTypeName(type) + ": "; CalculateAndDrawLabelCommonElement(typeName, 30f); GUI.Label(labelInputAreaRect, "(Null)", labelTextStyle); } else { string typeName = Utility.BeautifyTypeName(type) + ": "; string content = string.Format("Default({0})", type.Name); CalculateAndDrawLabelCommonElement(typeName, Utility.GetStringGuiWidth(content, labelTextStyle.fontSize)); GUI.Label(labelInputAreaRect, content, labelTextStyle); } }