diff --git a/Scripts/NodeDataCache.cs b/Scripts/NodeDataCache.cs index 4f4937d9..9ec08ed9 100644 --- a/Scripts/NodeDataCache.cs +++ b/Scripts/NodeDataCache.cs @@ -9,6 +9,7 @@ public static class NodeDataCache { private static PortDataCache portDataCache; private static Dictionary> formerlySerializedAsCache; private static Dictionary typeQualifiedNameCache; + private static List dynamicListPorts; private static bool Initialized { get { return portDataCache != null; } } public static string GetTypeQualifiedName(System.Type type) { @@ -26,18 +27,17 @@ public static string GetTypeQualifiedName(System.Type type) { public static void UpdatePorts(Node node, Dictionary ports) { if (!Initialized) BuildCache(); - Dictionary> removedPorts = new Dictionary>(); System.Type nodeType = node.GetType(); + Dictionary> removedPorts = null; Dictionary formerlySerializedAs = null; if (formerlySerializedAsCache != null) formerlySerializedAsCache.TryGetValue(nodeType, out formerlySerializedAs); - List dynamicListPorts = new List(); Dictionary staticPorts; if (!portDataCache.TryGetValue(nodeType, out staticPorts)) { - staticPorts = new Dictionary(); - } + staticPorts = new Dictionary(); + } // Cleanup port dict - Remove nonexisting static ports - update static port types // AND update dynamic ports (albeit only those in lists) too, in order to enforce proper serialisation. @@ -49,7 +49,10 @@ public static void UpdatePorts(Node node, Dictionary ports) { // If port exists but with wrong settings, remove it. Re-add it later. if (port.IsDynamic || port.direction != staticPort.direction || port.connectionType != staticPort.connectionType || port.typeConstraint != staticPort.typeConstraint) { // If port is not dynamic and direction hasn't changed, add it to the list so we can try reconnecting the ports connections. - if (!port.IsDynamic && port.direction == staticPort.direction) removedPorts.Add(port.fieldName, port.GetConnections()); + if (!port.IsDynamic && port.direction == staticPort.direction) { + if (removedPorts == null) removedPorts = new Dictionary>(); + removedPorts.Add(port.fieldName, port.GetConnections()); + } port.ClearConnections(); ports.Remove(port.fieldName); } else port.ValueType = staticPort.ValueType; @@ -59,7 +62,10 @@ public static void UpdatePorts(Node node, Dictionary ports) { //See if the field is tagged with FormerlySerializedAs, if so add the port with its new field name to removedPorts // so it can be reconnected in missing ports stage. string newName = null; - if (formerlySerializedAs != null && formerlySerializedAs.TryGetValue(port.fieldName, out newName)) removedPorts.Add(newName, port.GetConnections()); + if (formerlySerializedAs != null && formerlySerializedAs.TryGetValue(port.fieldName, out newName)) { + if (removedPorts == null) removedPorts = new Dictionary>(); + removedPorts.Add(newName, port.GetConnections()); + } port.ClearConnections(); ports.Remove(port.fieldName); @@ -69,13 +75,14 @@ public static void UpdatePorts(Node node, Dictionary ports) { dynamicListPorts.Add(port); } } + // Add missing ports foreach (NodePort staticPort in staticPorts.Values) { if (!ports.ContainsKey(staticPort.fieldName)) { NodePort port = new NodePort(staticPort, node); //If we just removed the port, try re-adding the connections List reconnectConnections; - if (removedPorts.TryGetValue(staticPort.fieldName, out reconnectConnections)) { + if (removedPorts != null && removedPorts.TryGetValue(staticPort.fieldName, out reconnectConnections)) { for (int i = 0; i < reconnectConnections.Count; i++) { NodePort connection = reconnectConnections[i]; if (connection == null) continue; @@ -102,6 +109,8 @@ public static void UpdatePorts(Node node, Dictionary ports) { listPort.connectionType = backingPort.connectionType; listPort.typeConstraint = backingPort.typeConstraint; } + + dynamicListPorts.Clear(); } /// @@ -124,10 +133,11 @@ private static bool IsDynamicListPort(NodePort port) { // Ports flagged as "dynamicPortList = true" end up having a "backing port" and a name with an index, but we have // no guarantee that a dynamic port called "output 0" is an element in a list backed by a static "output" port. // Thus, we need to check for attributes... (but at least we don't need to look at all fields this time) - string[] fieldNameParts = port.fieldName.Split(' '); - if (fieldNameParts.Length != 2) return false; + int fieldNameSpaceIndex = port.fieldName.IndexOf(' '); + if (fieldNameSpaceIndex < 0) return false; + string fieldNamePart = port.fieldName.Substring(0, fieldNameSpaceIndex); - FieldInfo backingPortInfo = port.node.GetType().GetField(fieldNameParts[0]); + FieldInfo backingPortInfo = port.node.GetType().GetField(fieldNamePart); if (backingPortInfo == null) return false; object[] attribs = backingPortInfo.GetCustomAttributes(true); @@ -142,6 +152,11 @@ private static bool IsDynamicListPort(NodePort port) { /// Cache node types private static void BuildCache() { portDataCache = new PortDataCache(); + dynamicListPorts = new List(); + +#if UNITY_2019_2_OR_NEWER && UNITY_EDITOR + List nodeTypes = UnityEditor.TypeCache.GetTypesDerivedFrom().Where(type => !type.IsAbstract).ToList(); +#else System.Type baseType = typeof(Node); List nodeTypes = new List(); System.Reflection.Assembly[] assemblies = System.AppDomain.CurrentDomain.GetAssemblies(); @@ -166,6 +181,7 @@ private static void BuildCache() { break; } } +#endif for (int i = 0; i < nodeTypes.Count; i++) { CachePorts(nodeTypes[i]); @@ -206,8 +222,8 @@ private static void CachePorts(System.Type nodeType) { if (inputAttrib != null && outputAttrib != null) Debug.LogError("Field " + fieldInfo[i].Name + " of type " + nodeType.FullName + " cannot be both input and output."); else { if (!portDataCache.ContainsKey(nodeType)) portDataCache.Add(nodeType, new Dictionary()); - NodePort port = new NodePort(fieldInfo[i]); - portDataCache[nodeType].Add(port.fieldName, port); + NodePort port = new NodePort(fieldInfo[i]); + portDataCache[nodeType].Add(port.fieldName, port); } if (formerlySerializedAsAttribute != null) { @@ -220,7 +236,6 @@ private static void CachePorts(System.Type nodeType) { } } - [System.Serializable] private class PortDataCache : Dictionary> { } } }