private void LoadGraph(BinaryReader stream) { // IMPORTANT! This must match C++ Graph format // Magic Code int tmp = stream.ReadInt32(); if (tmp != 1963542358) { // Error throw new Exception("Invalid Graph format version"); } // Version var version = stream.ReadUInt32(); var tmpHints = _cachedConnections.Value; var guidBytes = new byte[16]; if (version < 7000) { // Time saved (not used anymore to prevent binary diffs after saving unmodified surface) stream.ReadInt64(); // Nodes count int nodesCount = stream.ReadInt32(); if (Nodes.Capacity < nodesCount) { Nodes.Capacity = nodesCount; } tmpHints.Clear(); tmpHints.Capacity = Mathf.Max(tmpHints.Capacity, nodesCount * 4); // Parameters count int parametersCount = stream.ReadInt32(); if (Parameters.Capacity < parametersCount) { Parameters.Capacity = parametersCount; } // For each node for (int i = 0; i < nodesCount; i++) { // ID uint id = stream.ReadUInt32(); // Type ushort typeId = stream.ReadUInt16(); ushort groupId = stream.ReadUInt16(); // Create node SurfaceNode node; if (groupId == Archetypes.Custom.GroupID) { node = new DummyCustomNode(id, this); } else { node = NodeFactory.CreateNode(_surface.NodeArchetypes, id, this, groupId, typeId); } if (node == null) { node = new MissingNode(id, this, groupId, typeId); } Nodes.Add(node); } // For each param for (int i = 0; i < parametersCount; i++) { // Create param var param = new SurfaceParameter(); Parameters.Add(param); // Properties param.Type = new ScriptType(GetGraphParameterValueType((GraphParamType_Deprecated)stream.ReadByte())); stream.Read(guidBytes, 0, 16); param.ID = new Guid(guidBytes); param.Name = stream.ReadStr(97); param.IsPublic = stream.ReadByte() != 0; bool isStatic = stream.ReadByte() != 0; bool isUIVisible = stream.ReadByte() != 0; bool isUIEditable = stream.ReadByte() != 0; // References [Deprecated] int refsCount = stream.ReadInt32(); for (int j = 0; j < refsCount; j++) { uint refID = stream.ReadUInt32(); } // Value stream.ReadCommonValue(ref param.Value); // Meta param.Meta.Load(stream); } // For each node for (int i = 0; i < nodesCount; i++) { var node = Nodes[i]; int valuesCnt = stream.ReadInt32(); int firstValueReadIdx = 0; // Special case for missing nodes if (node is DummyCustomNode customNode) { node = null; // Values check if (valuesCnt < 2) { throw new Exception("Missing custom nodes data."); } // Node typename check object typeNameValue = null; stream.ReadCommonValue(ref typeNameValue); firstValueReadIdx = 1; string typeName = typeNameValue as string ?? string.Empty; // Find custom node archetype that matches this node type (it must be unique) var customNodes = _surface.GetCustomNodes(); if (customNodes?.Archetypes != null && typeName.Length != 0) { NodeArchetype arch = null; foreach (var nodeArchetype in customNodes.Archetypes) { if (string.Equals(Archetypes.Custom.GetNodeTypeName(nodeArchetype), typeName, StringComparison.OrdinalIgnoreCase)) { arch = nodeArchetype; break; } } if (arch != null) { node = NodeFactory.CreateNode(customNode.ID, this, customNodes, arch); } } // Fallback to the if (node == null) { Editor.LogWarning(string.Format("Cannot find custom node archetype for {0}", typeName)); node = new MissingNode(customNode.ID, this, Archetypes.Custom.GroupID, customNode.Archetype.TypeID); } Nodes[i] = node; // Store node typename in values container node.Values[0] = typeName; } if (node is MissingNode) { // Read all values Array.Resize(ref node.Values, valuesCnt); for (int j = firstValueReadIdx; j < valuesCnt; j++) { // ReSharper disable once PossibleNullReferenceException stream.ReadCommonValue(ref node.Values[j]); } firstValueReadIdx = valuesCnt = node.Values.Length; } // Values int nodeValuesCnt = node.Values?.Length ?? 0; if (valuesCnt == nodeValuesCnt) { for (int j = firstValueReadIdx; j < valuesCnt; j++) { // ReSharper disable once PossibleNullReferenceException stream.ReadCommonValue(ref node.Values[j]); } } else { Editor.LogWarning(string.Format("Invalid node values. Loaded: {0}, expected: {1}. Type: {2}, {3}", valuesCnt, nodeValuesCnt, node.Archetype.Title, node.Archetype.TypeID)); object dummy = null; for (int j = firstValueReadIdx; j < valuesCnt; j++) { stream.ReadCommonValue(ref dummy); if (j < nodeValuesCnt && dummy != null && node.Values[j] != null && node.Values[j].GetType() == dummy.GetType()) { node.Values[j] = dummy; } } } // Boxes ushort boxesCount = stream.ReadUInt16(); for (int j = 0; j < boxesCount; j++) { var id = stream.ReadByte(); stream.ReadUInt32(); // Skip type ushort connectionsCnt = stream.ReadUInt16(); ConnectionHint hint; hint.NodeB = node.ID; hint.BoxB = id; for (int k = 0; k < connectionsCnt; k++) { uint targetNodeID = stream.ReadUInt32(); byte targetBoxID = stream.ReadByte(); hint.NodeA = targetNodeID; hint.BoxA = targetBoxID; tmpHints.Add(hint); } } // Meta node.Meta.Load(stream); OnControlLoaded(node); } } else if (version == 7000) { // Nodes count int nodesCount = stream.ReadInt32(); if (Nodes.Capacity < nodesCount) { Nodes.Capacity = nodesCount; } tmpHints.Clear(); tmpHints.Capacity = Mathf.Max(tmpHints.Capacity, nodesCount * 4); // Parameters count int parametersCount = stream.ReadInt32(); if (Parameters.Capacity < parametersCount) { Parameters.Capacity = parametersCount; } // For each node for (int i = 0; i < nodesCount; i++) { uint id = stream.ReadUInt32(); ushort typeId = stream.ReadUInt16(); ushort groupId = stream.ReadUInt16(); // Create node SurfaceNode node; if (groupId == Archetypes.Custom.GroupID) { node = new DummyCustomNode(id, this); } else { node = NodeFactory.CreateNode(_surface.NodeArchetypes, id, this, groupId, typeId); } if (node == null) { node = new MissingNode(id, this, groupId, typeId); } Nodes.Add(node); } // For each param for (int i = 0; i < parametersCount; i++) { // Create param var param = new SurfaceParameter(); Parameters.Add(param); param.Type = stream.ReadVariantScriptType(); stream.Read(guidBytes, 0, 16); param.ID = new Guid(guidBytes); param.Name = stream.ReadStr(97); param.IsPublic = stream.ReadByte() != 0; // Value param.Value = stream.ReadVariant(); // Meta param.Meta.Load(stream); } // For each node for (int i = 0; i < nodesCount; i++) { var node = Nodes[i]; int valuesCnt = stream.ReadInt32(); int firstValueReadIdx = 0; // Special case for missing nodes if (node is DummyCustomNode customNode) { node = null; // Values check if (valuesCnt < 2) { throw new Exception("Missing custom nodes data."); } // Node typename check object typeNameValue = stream.ReadVariant(); firstValueReadIdx = 1; string typeName = typeNameValue as string ?? string.Empty; // Find custom node archetype that matches this node type (it must be unique) var customNodes = _surface.GetCustomNodes(); if (customNodes?.Archetypes != null && typeName.Length != 0) { NodeArchetype arch = null; foreach (var nodeArchetype in customNodes.Archetypes) { if (string.Equals(Archetypes.Custom.GetNodeTypeName(nodeArchetype), typeName, StringComparison.OrdinalIgnoreCase)) { arch = nodeArchetype; break; } } if (arch != null) { node = NodeFactory.CreateNode(customNode.ID, this, customNodes, arch); } } // Fallback to the if (node == null) { Editor.LogWarning(string.Format("Cannot find custom node archetype for {0}", typeName)); node = new MissingNode(customNode.ID, this, Archetypes.Custom.GroupID, customNode.Archetype.TypeID); } Nodes[i] = node; // Store node typename in values container node.Values[0] = typeName; } if (node is MissingNode) { // Read all values Array.Resize(ref node.Values, valuesCnt); for (int j = firstValueReadIdx; j < valuesCnt; j++) { node.Values[j] = stream.ReadVariant(); } firstValueReadIdx = valuesCnt = node.Values.Length; } // Values int nodeValuesCnt = node.Values?.Length ?? 0; if (valuesCnt == nodeValuesCnt) { for (int j = firstValueReadIdx; j < valuesCnt; j++) { node.Values[j] = stream.ReadVariant(); } } else { Editor.LogWarning(string.Format("Invalid node values. Loaded: {0}, expected: {1}. Type: {2}, {3}", valuesCnt, nodeValuesCnt, node.Archetype.Title, node.Archetype.TypeID)); object dummy; for (int j = firstValueReadIdx; j < valuesCnt; j++) { dummy = stream.ReadVariant(); if (j < nodeValuesCnt && dummy != null && node.Values[j] != null && node.Values[j].GetType() == dummy.GetType()) { node.Values[j] = dummy; } } } // Boxes ushort boxesCount = stream.ReadUInt16(); for (int j = 0; j < boxesCount; j++) { var id = stream.ReadByte(); stream.ReadVariantType(); // Skip type var connectionsCnt = stream.ReadUInt16(); ConnectionHint hint; hint.NodeB = node.ID; hint.BoxB = id; for (int k = 0; k < connectionsCnt; k++) { uint targetNodeID = stream.ReadUInt32(); byte targetBoxID = stream.ReadByte(); hint.NodeA = targetNodeID; hint.BoxA = targetBoxID; tmpHints.Add(hint); } } // Meta node.Meta.Load(stream); OnControlLoaded(node); } } else { throw new Exception($"Unsupported graph version {version}."); } // Visject Meta _meta.Load(stream); // Setup connections for (int i = 0; i < tmpHints.Count; i++) { var c = tmpHints[i]; var nodeA = FindNode(c.NodeA); var nodeB = FindNode(c.NodeB); if (nodeA == null || nodeB == null) { // Error Editor.LogWarning("Invalid connected node id."); continue; } var boxA = nodeA.GetBox(c.BoxA); var boxB = nodeB.GetBox(c.BoxB); if (boxA != null && boxB != null) { boxA.Connections.Add(boxB); } } // Ending char byte end = stream.ReadByte(); if (end != '\t') { throw new Exception("Invalid data."); } }
/// <inheritdoc /> public override bool CanUseNodeType(NodeArchetype nodeArchetype) { return((nodeArchetype.Flags & NodeFlags.MaterialGraph) != 0 && base.CanUseNodeType(nodeArchetype)); }
/// <inheritdoc /> public override bool CanSpawnNodeType(NodeArchetype nodeArchetype) { return((nodeArchetype.Flags & NodeFlags.ParticleEmitterGraph) != 0 && base.CanSpawnNodeType(nodeArchetype)); }