mirror of
https://github.com/Siccity/xNode.git
synced 2025-12-21 01:36:03 +08:00
Merge pull request #2 from insthync/merge--siccity-master
Merge siccity master
This commit is contained in:
commit
a8ef96ce1b
12
Scripts/Attributes/PortTypeOverrideAttribute.cs
Normal file
12
Scripts/Attributes/PortTypeOverrideAttribute.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
/// <summary> Overrides the ValueType of the Port, to have a ValueType different from the type of its serializable field </summary>
|
||||||
|
/// <remarks> Especially useful in Dynamic Port Lists to create Value-Port Pairs with different type. </remarks>
|
||||||
|
[AttributeUsage(AttributeTargets.Field)]
|
||||||
|
public class PortTypeOverrideAttribute : Attribute {
|
||||||
|
public Type type;
|
||||||
|
/// <summary> Overrides the ValueType of the Port </summary>
|
||||||
|
/// <param name="type">ValueType of the Port</param>
|
||||||
|
public PortTypeOverrideAttribute(Type type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Scripts/Attributes/PortTypeOverrideAttribute.cs.meta
Normal file
11
Scripts/Attributes/PortTypeOverrideAttribute.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1410c1437e863ab4fac7a7428aaca35b
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
@ -12,8 +12,8 @@ namespace XNodeEditor {
|
|||||||
/// <summary> Contains GUI methods </summary>
|
/// <summary> Contains GUI methods </summary>
|
||||||
public partial class NodeEditorWindow {
|
public partial class NodeEditorWindow {
|
||||||
public NodeGraphEditor graphEditor;
|
public NodeGraphEditor graphEditor;
|
||||||
private List<UnityEngine.Object> selectionCache;
|
private readonly HashSet<UnityEngine.Object> selectionCache = new();
|
||||||
private List<XNode.Node> culledNodes;
|
private readonly HashSet<XNode.Node> culledNodes = new();
|
||||||
/// <summary> 19 if docked, 22 if not </summary>
|
/// <summary> 19 if docked, 22 if not </summary>
|
||||||
private int topPadding { get { return isDocked() ? 19 : 22; } }
|
private int topPadding { get { return isDocked() ? 19 : 22; } }
|
||||||
/// <summary> Executed after all other window GUI. Useful if Zoom is ruining your day. Automatically resets after being run.</summary>
|
/// <summary> Executed after all other window GUI. Useful if Zoom is ruining your day. Automatically resets after being run.</summary>
|
||||||
@ -399,8 +399,13 @@ namespace XNodeEditor {
|
|||||||
|
|
||||||
private void DrawNodes() {
|
private void DrawNodes() {
|
||||||
Event e = Event.current;
|
Event e = Event.current;
|
||||||
|
|
||||||
if (e.type == EventType.Layout) {
|
if (e.type == EventType.Layout) {
|
||||||
selectionCache = new List<UnityEngine.Object>(Selection.objects);
|
selectionCache.Clear();
|
||||||
|
var objs = Selection.objects;
|
||||||
|
selectionCache.EnsureCapacity(objs.Length);
|
||||||
|
foreach (var obj in objs)
|
||||||
|
selectionCache.Add(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
System.Reflection.MethodInfo onValidate = null;
|
System.Reflection.MethodInfo onValidate = null;
|
||||||
@ -432,7 +437,7 @@ namespace XNodeEditor {
|
|||||||
|
|
||||||
List<XNode.NodePort> removeEntries = new List<XNode.NodePort>();
|
List<XNode.NodePort> removeEntries = new List<XNode.NodePort>();
|
||||||
|
|
||||||
if (e.type == EventType.Layout) culledNodes = new List<XNode.Node>();
|
if (e.type == EventType.Layout) culledNodes.Clear();
|
||||||
for (int n = 0; n < graph.nodes.Count; n++) {
|
for (int n = 0; n < graph.nodes.Count; n++) {
|
||||||
// Skip null nodes. The user could be in the process of renaming scripts, so removing them at this point is not advisable.
|
// Skip null nodes. The user could be in the process of renaming scripts, so removing them at this point is not advisable.
|
||||||
if (graph.nodes[n] == null) continue;
|
if (graph.nodes[n] == null) continue;
|
||||||
|
|||||||
@ -399,6 +399,8 @@ namespace XNode {
|
|||||||
public void OnBeforeSerialize() {
|
public void OnBeforeSerialize() {
|
||||||
keys.Clear();
|
keys.Clear();
|
||||||
values.Clear();
|
values.Clear();
|
||||||
|
keys.Capacity = this.Count;
|
||||||
|
values.Capacity = this.Count;
|
||||||
foreach (KeyValuePair<string, NodePort> pair in this) {
|
foreach (KeyValuePair<string, NodePort> pair in this) {
|
||||||
keys.Add(pair.Key);
|
keys.Add(pair.Key);
|
||||||
values.Add(pair.Value);
|
values.Add(pair.Value);
|
||||||
@ -407,6 +409,9 @@ namespace XNode {
|
|||||||
|
|
||||||
public void OnAfterDeserialize() {
|
public void OnAfterDeserialize() {
|
||||||
this.Clear();
|
this.Clear();
|
||||||
|
#if UNITY_2021_3_OR_NEWER
|
||||||
|
this.EnsureCapacity(keys.Count);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (keys.Count != values.Count)
|
if (keys.Count != values.Count)
|
||||||
throw new System.Exception("there are " + keys.Count + " keys and " + values.Count + " values after deserialization. Make sure that both key and value types are serializable.");
|
throw new System.Exception("there are " + keys.Count + " keys and " + values.Count + " values after deserialization. Make sure that both key and value types are serializable.");
|
||||||
|
|||||||
@ -8,13 +8,24 @@ namespace XNode {
|
|||||||
public static class NodeDataCache {
|
public static class NodeDataCache {
|
||||||
private static PortDataCache portDataCache;
|
private static PortDataCache portDataCache;
|
||||||
private static Dictionary<System.Type, Dictionary<string, string>> formerlySerializedAsCache;
|
private static Dictionary<System.Type, Dictionary<string, string>> formerlySerializedAsCache;
|
||||||
|
private static Dictionary<System.Type, string> typeQualifiedNameCache;
|
||||||
private static bool Initialized { get { return portDataCache != null; } }
|
private static bool Initialized { get { return portDataCache != null; } }
|
||||||
|
|
||||||
|
public static string GetTypeQualifiedName(System.Type type) {
|
||||||
|
if(typeQualifiedNameCache == null) typeQualifiedNameCache = new Dictionary<System.Type, string>();
|
||||||
|
|
||||||
|
string name;
|
||||||
|
if (!typeQualifiedNameCache.TryGetValue(type, out name)) {
|
||||||
|
name = type.AssemblyQualifiedName;
|
||||||
|
typeQualifiedNameCache.Add(type, name);
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary> Update static ports and dynamic ports managed by DynamicPortLists to reflect class fields. </summary>
|
/// <summary> Update static ports and dynamic ports managed by DynamicPortLists to reflect class fields. </summary>
|
||||||
public static void UpdatePorts(Node node, Dictionary<string, NodePort> ports) {
|
public static void UpdatePorts(Node node, Dictionary<string, NodePort> ports) {
|
||||||
if (!Initialized) BuildCache();
|
if (!Initialized) BuildCache();
|
||||||
|
|
||||||
Dictionary<string, NodePort> staticPorts = new Dictionary<string, NodePort>();
|
|
||||||
Dictionary<string, List<NodePort>> removedPorts = new Dictionary<string, List<NodePort>>();
|
Dictionary<string, List<NodePort>> removedPorts = new Dictionary<string, List<NodePort>>();
|
||||||
System.Type nodeType = node.GetType();
|
System.Type nodeType = node.GetType();
|
||||||
|
|
||||||
@ -23,17 +34,15 @@ namespace XNode {
|
|||||||
|
|
||||||
List<NodePort> dynamicListPorts = new List<NodePort>();
|
List<NodePort> dynamicListPorts = new List<NodePort>();
|
||||||
|
|
||||||
List<NodePort> typePortCache;
|
Dictionary<string, NodePort> staticPorts;
|
||||||
if (portDataCache.TryGetValue(nodeType, out typePortCache)) {
|
if (!portDataCache.TryGetValue(nodeType, out staticPorts)) {
|
||||||
for (int i = 0; i < typePortCache.Count; i++) {
|
staticPorts = new Dictionary<string, NodePort>();
|
||||||
staticPorts.Add(typePortCache[i].fieldName, portDataCache[nodeType][i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup port dict - Remove nonexisting static ports - update static port types
|
// 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.
|
// AND update dynamic ports (albeit only those in lists) too, in order to enforce proper serialisation.
|
||||||
// Loop through current node ports
|
// Loop through current node ports
|
||||||
foreach (NodePort port in ports.Values.ToList()) {
|
foreach (NodePort port in ports.Values.ToArray()) {
|
||||||
// If port still exists, check it it has been changed
|
// If port still exists, check it it has been changed
|
||||||
NodePort staticPort;
|
NodePort staticPort;
|
||||||
if (staticPorts.TryGetValue(port.fieldName, out staticPort)) {
|
if (staticPorts.TryGetValue(port.fieldName, out staticPort)) {
|
||||||
@ -84,7 +93,7 @@ namespace XNode {
|
|||||||
foreach (NodePort listPort in dynamicListPorts) {
|
foreach (NodePort listPort in dynamicListPorts) {
|
||||||
// At this point we know that ports here are dynamic list ports
|
// At this point we know that ports here are dynamic list ports
|
||||||
// which have passed name/"backing port" checks, ergo we can proceed more safely.
|
// which have passed name/"backing port" checks, ergo we can proceed more safely.
|
||||||
string backingPortName = listPort.fieldName.Split(' ')[0];
|
string backingPortName = listPort.fieldName.Substring(0, listPort.fieldName.IndexOf(' '));
|
||||||
NodePort backingPort = staticPorts[backingPortName];
|
NodePort backingPort = staticPorts[backingPortName];
|
||||||
|
|
||||||
// Update port constraints. Creating a new port instead will break the editor, mandating the need for setters.
|
// Update port constraints. Creating a new port instead will break the editor, mandating the need for setters.
|
||||||
@ -147,6 +156,7 @@ namespace XNode {
|
|||||||
// The following assemblies, and sub-assemblies (eg. UnityEngine.UI) are skipped
|
// The following assemblies, and sub-assemblies (eg. UnityEngine.UI) are skipped
|
||||||
case "UnityEditor":
|
case "UnityEditor":
|
||||||
case "UnityEngine":
|
case "UnityEngine":
|
||||||
|
case "Unity":
|
||||||
case "System":
|
case "System":
|
||||||
case "mscorlib":
|
case "mscorlib":
|
||||||
case "Microsoft":
|
case "Microsoft":
|
||||||
@ -154,11 +164,11 @@ namespace XNode {
|
|||||||
default:
|
default:
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
nodeTypes.AddRange(assembly.GetTypes().Where(t => !t.IsAbstract && baseType.IsAssignableFrom(t)).ToArray());
|
nodeTypes.AddRange(assembly.GetTypes().Where(t => !t.IsAbstract && baseType.IsAssignableFrom(t)).ToArray());
|
||||||
}
|
}
|
||||||
catch (System.Exception ex)
|
catch (System.Exception ex)
|
||||||
{
|
{
|
||||||
Debug.LogError("Catched exception when building " + assemblyName + " caches");
|
Debug.LogError($"Catched exception when building {assemblyName} caches");
|
||||||
Debug.LogException(ex);
|
Debug.LogException(ex);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -203,8 +213,9 @@ namespace XNode {
|
|||||||
|
|
||||||
if (inputAttrib != null && outputAttrib != null) Debug.LogError("Field " + fieldInfo[i].Name + " of type " + nodeType.FullName + " cannot be both input and output.");
|
if (inputAttrib != null && outputAttrib != null) Debug.LogError("Field " + fieldInfo[i].Name + " of type " + nodeType.FullName + " cannot be both input and output.");
|
||||||
else {
|
else {
|
||||||
if (!portDataCache.ContainsKey(nodeType)) portDataCache.Add(nodeType, new List<NodePort>());
|
if (!portDataCache.ContainsKey(nodeType)) portDataCache.Add(nodeType, new Dictionary<string, NodePort>());
|
||||||
portDataCache[nodeType].Add(new NodePort(fieldInfo[i]));
|
NodePort port = new NodePort(fieldInfo[i]);
|
||||||
|
portDataCache[nodeType].Add(port.fieldName, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (formerlySerializedAsAttribute != null) {
|
if (formerlySerializedAsAttribute != null) {
|
||||||
@ -218,30 +229,6 @@ namespace XNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[System.Serializable]
|
[System.Serializable]
|
||||||
private class PortDataCache : Dictionary<System.Type, List<NodePort>>, ISerializationCallbackReceiver {
|
private class PortDataCache : Dictionary<System.Type, Dictionary<string, NodePort>> { }
|
||||||
[SerializeField] private List<System.Type> keys = new List<System.Type>();
|
|
||||||
[SerializeField] private List<List<NodePort>> values = new List<List<NodePort>>();
|
|
||||||
|
|
||||||
// save the dictionary to lists
|
|
||||||
public void OnBeforeSerialize() {
|
|
||||||
keys.Clear();
|
|
||||||
values.Clear();
|
|
||||||
foreach (var pair in this) {
|
|
||||||
keys.Add(pair.Key);
|
|
||||||
values.Add(pair.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// load dictionary from lists
|
|
||||||
public void OnAfterDeserialize() {
|
|
||||||
this.Clear();
|
|
||||||
|
|
||||||
if (keys.Count != values.Count)
|
|
||||||
throw new System.Exception(string.Format("there are {0} keys and {1} values after deserialization. Make sure that both key and value types are serializable.", keys.Count, values.Count));
|
|
||||||
|
|
||||||
for (int i = 0; i < keys.Count; i++)
|
|
||||||
this.Add(keys[i], values[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,7 +47,7 @@ namespace XNode {
|
|||||||
public virtual void Clear() {
|
public virtual void Clear() {
|
||||||
if (Application.isPlaying) {
|
if (Application.isPlaying) {
|
||||||
for (int i = 0; i < nodes.Count; i++) {
|
for (int i = 0; i < nodes.Count; i++) {
|
||||||
Destroy(nodes[i]);
|
if (nodes[i] != null) Destroy(nodes[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nodes.Clear();
|
nodes.Clear();
|
||||||
|
|||||||
@ -47,8 +47,9 @@ namespace XNode {
|
|||||||
return valueType;
|
return valueType;
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
|
if (valueType == value) return;
|
||||||
valueType = value;
|
valueType = value;
|
||||||
if (value != null) _typeQualifiedName = value.AssemblyQualifiedName;
|
if (value != null) _typeQualifiedName = NodeDataCache.GetTypeQualifiedName(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private Type valueType;
|
private Type valueType;
|
||||||
@ -78,6 +79,10 @@ namespace XNode {
|
|||||||
_connectionType = (attribs[i] as Node.OutputAttribute).connectionType;
|
_connectionType = (attribs[i] as Node.OutputAttribute).connectionType;
|
||||||
_typeConstraint = (attribs[i] as Node.OutputAttribute).typeConstraint;
|
_typeConstraint = (attribs[i] as Node.OutputAttribute).typeConstraint;
|
||||||
}
|
}
|
||||||
|
// Override ValueType of the Port
|
||||||
|
if(attribs[i] is PortTypeOverrideAttribute) {
|
||||||
|
ValueType = (attribs[i] as PortTypeOverrideAttribute).type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user