/// <summary> /// Exports the given simplified canvas data to the location specified in the args (usually string[1] containing the path) /// </summary> public abstract void ExportData(CanvasData data, params object[] locationArgs);
public override void Export(NodeCanvas canvas, params object[] locationArgs) { CanvasData data = ImportExportManager.ConvertToCanvasData(canvas); ExportData(data, locationArgs); }
public override void ExportData(CanvasData data, params object[] args) { if (args == null || args.Length != 1 || args[0].GetType() != typeof(string)) { throw new ArgumentException("Location Arguments"); } string path = (string)args[0]; XmlDocument saveDoc = new XmlDocument(); XmlDeclaration decl = saveDoc.CreateXmlDeclaration("1.0", "UTF-8", null); saveDoc.InsertBefore(decl, saveDoc.DocumentElement); // CANVAS XmlElement canvas = saveDoc.CreateElement("NodeCanvas"); canvas.SetAttribute("type", data.type.FullName); saveDoc.AppendChild(canvas); // EDITOR STATES XmlElement editorStates = saveDoc.CreateElement("EditorStates"); canvas.AppendChild(editorStates); foreach (EditorStateData stateData in data.editorStates) { XmlElement editorState = saveDoc.CreateElement("EditorState"); editorState.SetAttribute("selected", stateData.selectedNode != null ? stateData.selectedNode.nodeID.ToString() : ""); editorState.SetAttribute("pan", stateData.panOffset.x + "," + stateData.panOffset.y); editorState.SetAttribute("zoom", stateData.zoom.ToString()); editorStates.AppendChild(editorState); } // GROUPS XmlElement groups = saveDoc.CreateElement("Groups"); canvas.AppendChild(groups); foreach (GroupData groupData in data.groups) { XmlElement group = saveDoc.CreateElement("Group"); group.SetAttribute("name", groupData.name); group.SetAttribute("rect", groupData.rect.x + "," + groupData.rect.y + "," + groupData.rect.width + "," + groupData.rect.height); group.SetAttribute("color", groupData.color.r + "," + groupData.color.g + "," + groupData.color.b + "," + groupData.color.a); groups.AppendChild(group); } // NODES XmlElement nodes = saveDoc.CreateElement("Nodes"); canvas.AppendChild(nodes); foreach (NodeData nodeData in data.nodes.Values) { XmlElement node = saveDoc.CreateElement("Node"); node.SetAttribute("name", nodeData.name); node.SetAttribute("ID", nodeData.nodeID.ToString()); node.SetAttribute("type", nodeData.typeID); node.SetAttribute("pos", nodeData.nodePos.x + "," + nodeData.nodePos.y); nodes.AppendChild(node); // NODE PORTS foreach (PortData portData in nodeData.connectionPorts) { XmlElement port = saveDoc.CreateElement("Port"); port.SetAttribute("ID", portData.portID.ToString()); port.SetAttribute("name", portData.name); port.SetAttribute("dynamic", portData.dynamic.ToString()); if (portData.dynamic) { // Serialize dynamic port port.SetAttribute("type", portData.dynaType.AssemblyQualifiedName); foreach (string fieldName in portData.port.AdditionalDynamicKnobData()) { SerializeFieldToXML(port, portData.port, fieldName); // Serialize all dynamic knob variables } } node.AppendChild(port); } // NODE VARIABLES foreach (VariableData varData in nodeData.variables) { // Serialize all node variables if (varData.refObject != null) { // Serialize reference-type variables as 'Variable' element XmlElement variable = saveDoc.CreateElement("Variable"); variable.SetAttribute("name", varData.name); variable.SetAttribute("refID", varData.refObject.refID.ToString()); node.AppendChild(variable); } else // Serialize value-type fields in-line { XmlElement serializedValue = SerializeObjectToXML(node, varData.value); if (serializedValue != null) { serializedValue.SetAttribute("name", varData.name); } } } } // CONNECTIONS XmlElement connections = saveDoc.CreateElement("Connections"); canvas.AppendChild(connections); foreach (ConnectionData connectionData in data.connections) { XmlElement connection = saveDoc.CreateElement("Connection"); connection.SetAttribute("port1ID", connectionData.port1.portID.ToString()); connection.SetAttribute("port2ID", connectionData.port2.portID.ToString()); connections.AppendChild(connection); } // OBJECTS XmlElement objects = saveDoc.CreateElement("Objects"); canvas.AppendChild(objects); foreach (ObjectData objectData in data.objects.Values) { XmlElement obj = saveDoc.CreateElement("Object"); obj.SetAttribute("refID", objectData.refID.ToString()); obj.SetAttribute("type", objectData.data.GetType().FullName); if (SerializeObjectToXML(obj, objectData.data) != null) { objects.AppendChild(obj); } } // WRITE Directory.CreateDirectory(Path.GetDirectoryName(path)); using (XmlTextWriter writer = new XmlTextWriter(path, Encoding.UTF8)) { writer.Formatting = Formatting.Indented; writer.Indentation = 1; writer.IndentChar = '\t'; saveDoc.Save(writer); } }
public override CanvasData ImportData(params object[] args) { if (args == null || args.Length != 1 || args[0].GetType() != typeof(string)) { throw new ArgumentException("Location Arguments"); } string path = (string)args[0]; using (FileStream fs = new FileStream(path, FileMode.Open)) { XmlDocument data = new XmlDocument(); data.Load(fs); // CANVAS string canvasName = Path.GetFileNameWithoutExtension(path); XmlElement xmlCanvas = (XmlElement)data.SelectSingleNode("//NodeCanvas"); Type canvasType = NodeCanvasManager.GetCanvasTypeData(xmlCanvas.GetAttribute("type")).CanvasType; if (canvasType == null) { throw new XmlException("Could not find NodeCanvas of type '" + xmlCanvas.GetAttribute("type") + "'!"); } CanvasData canvasData = new CanvasData(canvasType, canvasName); Dictionary <int, PortData> ports = new Dictionary <int, PortData>(); // OBJECTS IEnumerable <XmlElement> xmlObjects = xmlCanvas.SelectNodes("Objects/Object").OfType <XmlElement>(); foreach (XmlElement xmlObject in xmlObjects) { int refID = GetIntegerAttribute(xmlObject, "refID"); string typeName = xmlObject.GetAttribute("type"); Type type = Type.GetType(typeName, true); object obj = DeserializeObjectFromXML(xmlObject, type); ObjectData objData = new ObjectData(refID, obj); canvasData.objects.Add(refID, objData); } // NODES IEnumerable <XmlElement> xmlNodes = xmlCanvas.SelectNodes("Nodes/Node").OfType <XmlElement>(); foreach (XmlElement xmlNode in xmlNodes) { string name = xmlNode.GetAttribute("name"); int nodeID = GetIntegerAttribute(xmlNode, "ID"); string typeID = xmlNode.GetAttribute("type"); Vector2 nodePos = GetVectorAttribute(xmlNode, "pos"); // Record NodeData node = new NodeData(name, typeID, nodeID, nodePos); canvasData.nodes.Add(nodeID, node); // NODE PORTS IEnumerable <XmlElement> xmlConnectionPorts = xmlNode.SelectNodes("Port").OfType <XmlElement>(); foreach (XmlElement xmlPort in xmlConnectionPorts) { int portID = GetIntegerAttribute(xmlPort, "ID"); string portName = xmlPort.GetAttribute("name"); if (string.IsNullOrEmpty(portName)) // Fallback to old save { portName = xmlPort.GetAttribute("varName"); } bool dynamic = GetBooleanAttribute(xmlPort, "dynamic", false); PortData portData; if (!dynamic) // Record static port { portData = new PortData(node, portName, portID); } else { // Deserialize dynamic port string typeName = xmlPort.GetAttribute("type"); Type portType = Type.GetType(typeName, true); if (portType != typeof(ConnectionPort) && !portType.IsSubclassOf(typeof(ConnectionPort))) { continue; // Invalid type stored } ConnectionPort port = (ConnectionPort)ScriptableObject.CreateInstance(portType); port.name = portName; foreach (XmlElement portVar in xmlPort.ChildNodes.OfType <XmlElement>()) { DeserializeFieldFromXML(portVar, port); } portData = new PortData(node, port, portID); } node.connectionPorts.Add(portData); ports.Add(portID, portData); } // NODE VARIABLES foreach (XmlElement variable in xmlNode.ChildNodes.OfType <XmlElement>()) { // Deserialize all value-type variables if (variable.Name != "Variable" && variable.Name != "Port") { string varName = variable.GetAttribute("name"); object varValue = DeserializeFieldFromXML(variable, node.type, null); VariableData varData = new VariableData(varName); varData.value = varValue; node.variables.Add(varData); } } IEnumerable <XmlElement> xmlVariables = xmlNode.SelectNodes("Variable").OfType <XmlElement>(); foreach (XmlElement xmlVariable in xmlVariables) { // Deserialize all reference-type variables (and also value type variables in old save files) string varName = xmlVariable.GetAttribute("name"); VariableData varData = new VariableData(varName); if (xmlVariable.HasAttribute("refID")) { // Read reference-type variables from objects int refID = GetIntegerAttribute(xmlVariable, "refID"); ObjectData objData; if (canvasData.objects.TryGetValue(refID, out objData)) { varData.refObject = objData; } } else { // Read value-type variable (old save file only) TODO: Remove string typeName = xmlVariable.GetAttribute("type"); Type type = Type.GetType(typeName, true); varData.value = DeserializeObjectFromXML(xmlVariable, type); } node.variables.Add(varData); } } // CONNECTIONS IEnumerable <XmlElement> xmlConnections = xmlCanvas.SelectNodes("Connections/Connection").OfType <XmlElement>(); foreach (XmlElement xmlConnection in xmlConnections) { int port1ID = GetIntegerAttribute(xmlConnection, "port1ID"); int port2ID = GetIntegerAttribute(xmlConnection, "port2ID"); PortData port1, port2; if (ports.TryGetValue(port1ID, out port1) && ports.TryGetValue(port2ID, out port2)) { canvasData.RecordConnection(port1, port2); } } // GROUPS IEnumerable <XmlElement> xmlGroups = xmlCanvas.SelectNodes("Groups/Group").OfType <XmlElement>(); foreach (XmlElement xmlGroup in xmlGroups) { string name = xmlGroup.GetAttribute("name"); Rect rect = GetRectAttribute(xmlGroup, "rect"); Color color = GetColorAttribute(xmlGroup, "color"); canvasData.groups.Add(new GroupData(name, rect, color)); } // EDITOR STATES IEnumerable <XmlElement> xmlEditorStates = xmlCanvas.SelectNodes("EditorStates/EditorState").OfType <XmlElement>(); List <EditorStateData> editorStates = new List <EditorStateData>(); foreach (XmlElement xmlEditorState in xmlEditorStates) { Vector2 pan = GetVectorAttribute(xmlEditorState, "pan"); float zoom; if (!float.TryParse(xmlEditorState.GetAttribute("zoom"), out zoom)) { zoom = 1; } // Selected Node NodeData selectedNode = null; int selectedNodeID; if (int.TryParse(xmlEditorState.GetAttribute("selected"), out selectedNodeID)) { selectedNode = canvasData.FindNode(selectedNodeID); } // Create state editorStates.Add(new EditorStateData(selectedNode, pan, zoom)); } canvasData.editorStates = editorStates.ToArray(); return(canvasData); } }
/// <summary> /// Converts the simplified CanvasData back to a proper NodeCanvas /// </summary> internal static NodeCanvas ConvertToNodeCanvas(CanvasData canvasData) { if (canvasData == null) { return(null); } NodeCanvas nodeCanvas = NodeCanvas.CreateCanvas(canvasData.type); nodeCanvas.name = nodeCanvas.saveName = canvasData.name; nodeCanvas.nodes.Clear(); NodeEditor.BeginEditingCanvas(nodeCanvas); foreach (NodeData nodeData in canvasData.nodes.Values) { // Read all nodes Node node = Node.Create(nodeData.typeID, nodeData.nodePos, nodeCanvas, null, true, false); if (!string.IsNullOrEmpty(nodeData.name)) { node.name = nodeData.name; } if (node == null) { continue; } foreach (ConnectionPortDeclaration portDecl in ConnectionPortManager.GetPortDeclarationEnumerator(node)) { // Find stored ports for each node port declaration PortData portData = nodeData.connectionPorts.Find((PortData data) => data.name == portDecl.portField.Name); if (portData != null) // Stored port has been found, record { portData.port = (ConnectionPort)portDecl.portField.GetValue(node); } } foreach (PortData portData in nodeData.connectionPorts.Where(port => port.dynamic)) { // Find stored dynamic connection ports if (portData.port != null) // Stored port has been recreated { portData.port.body = node; node.dynamicConnectionPorts.Add(portData.port); } } foreach (VariableData varData in nodeData.variables) { // Restore stored variable to node FieldInfo field = node.GetType().GetField(varData.name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); if (field != null) { field.SetValue(node, varData.refObject != null ? varData.refObject.data : varData.value); } } } foreach (ConnectionData conData in canvasData.connections) { // Restore all connections if (conData.port1.port == null || conData.port2.port == null) { // Not all ports where saved in canvasData Debug.Log("Incomplete connection " + conData.port1.name + " and " + conData.port2.name + "!"); continue; } conData.port1.port.TryApplyConnection(conData.port2.port, true); } foreach (GroupData groupData in canvasData.groups) { // Recreate groups NodeGroup group = new NodeGroup(); group.title = groupData.name; group.rect = groupData.rect; group.color = groupData.color; nodeCanvas.groups.Add(group); } nodeCanvas.editorStates = new NodeEditorState[canvasData.editorStates.Length]; for (int i = 0; i < canvasData.editorStates.Length; i++) { // Read all editorStates EditorStateData stateData = canvasData.editorStates[i]; NodeEditorState state = ScriptableObject.CreateInstance <NodeEditorState>(); state.selectedNode = stateData.selectedNode == null ? null : canvasData.FindNode(stateData.selectedNode.nodeID).node; state.panOffset = stateData.panOffset; state.zoom = stateData.zoom; state.canvas = nodeCanvas; state.name = "EditorState"; nodeCanvas.editorStates[i] = state; } NodeEditor.EndEditingCanvas(); return(nodeCanvas); }
/// <summary> /// Converts the NodeCanvas to a simplified CanvasData /// </summary> internal static CanvasData ConvertToCanvasData(NodeCanvas canvas) { if (canvas == null) { return(null); } // Validate canvas and create canvas data for it canvas.Validate(); CanvasData canvasData = new CanvasData(canvas); // Store Lookup-Table for all ports Dictionary <ConnectionPort, PortData> portDatas = new Dictionary <ConnectionPort, PortData>(); foreach (Node node in canvas.nodes) { // Create node data NodeData nodeData = new NodeData(node); canvasData.nodes.Add(nodeData.nodeID, nodeData); foreach (ConnectionPortDeclaration portDecl in ConnectionPortManager.GetPortDeclarationEnumerator(node)) { // Fetch all static connection port declarations and record them ConnectionPort port = (ConnectionPort)portDecl.portField.GetValue(node); PortData portData = new PortData(nodeData, port, portDecl.portField.Name); nodeData.connectionPorts.Add(portData); portDatas.Add(port, portData); } foreach (ConnectionPort port in node.dynamicConnectionPorts) { // Fetch all dynamic connection ports and record them PortData portData = new PortData(nodeData, port); nodeData.connectionPorts.Add(portData); portDatas.Add(port, portData); } // Fetch all serialized node variables specific to each node's implementation FieldInfo[] serializedFields = ReflectionUtility.getSerializedFields(node.GetType(), typeof(Node)); foreach (FieldInfo field in serializedFields) { // Create variable data and enter the if (field.FieldType == typeof(ConnectionPort) || field.FieldType.IsSubclassOf(typeof(ConnectionPort))) { continue; } VariableData varData = new VariableData(field); nodeData.variables.Add(varData); object varValue = field.GetValue(node); if (field.FieldType.IsValueType || field.FieldType == typeof(string)) // Store value of the object { varData.value = varValue; } else // Store reference to the object { varData.refObject = canvasData.ReferenceObject(varValue); } } } foreach (PortData portData in portDatas.Values) { // Record the connections of this port foreach (ConnectionPort conPort in portData.port.connections) { PortData conPortData; // Get portData associated with the connection port if (portDatas.TryGetValue(conPort, out conPortData)) { canvasData.RecordConnection(portData, conPortData); } } } foreach (NodeGroup group in canvas.groups) { // Record all groups canvasData.groups.Add(new GroupData(group)); } canvasData.editorStates = new EditorStateData[canvas.editorStates.Length]; for (int i = 0; i < canvas.editorStates.Length; i++) { // Record all editorStates NodeEditorState state = canvas.editorStates[i]; NodeData selected = state.selectedNode == null ? null : canvasData.FindNode(state.selectedNode); canvasData.editorStates[i] = new EditorStateData(selected, state.panOffset, state.zoom); } return(canvasData); }