1
0
mirror of https://github.com/Siccity/xNode.git synced 2026-03-26 22:49:02 +08:00

!W Input新增了一个BaseType得指定,当TypeConstraint为TypeConstraint.Inherited时可用

This commit is contained in:
Icarus 2019-09-22 17:35:17 +08:00
parent ee68490c9b
commit 3a1b59480f
4 changed files with 60 additions and 19 deletions

View File

@ -254,8 +254,8 @@ namespace XNodeEditor {
} }
[Obsolete("Use DynamicPortList instead")] [Obsolete("Use DynamicPortList instead")]
public static void InstancePortList(string fieldName, Type type, SerializedObject serializedObject, XNode.NodePort.IO io, XNode.Node.ConnectionType connectionType = XNode.Node.ConnectionType.Multiple, XNode.Node.TypeConstraint typeConstraint = XNode.Node.TypeConstraint.None, Action<ReorderableList> onCreation = null) { public static void InstancePortList(string fieldName, Type type, SerializedObject serializedObject, XNode.NodePort.IO io, XNode.Node.ConnectionType connectionType = XNode.Node.ConnectionType.Multiple, XNode.Node.TypeConstraint typeConstraint = XNode.Node.TypeConstraint.None,Type inputTypeConstraintBaseType = null, Action<ReorderableList> onCreation = null) {
DynamicPortList(fieldName, type, serializedObject, io, connectionType, typeConstraint, onCreation); DynamicPortList(fieldName, type, serializedObject, io, connectionType, typeConstraint, inputTypeConstraintBaseType,onCreation);
} }
#endregion #endregion
@ -276,8 +276,9 @@ namespace XNodeEditor {
/// <param name="type">Value type of added dynamic ports</param> /// <param name="type">Value type of added dynamic ports</param>
/// <param name="serializedObject">The serializedObject of the node</param> /// <param name="serializedObject">The serializedObject of the node</param>
/// <param name="connectionType">Connection type of added dynamic ports</param> /// <param name="connectionType">Connection type of added dynamic ports</param>
/// <param name="inputTypeConstraintBaseType">当<see cref="io"/>为<see cref="IO.Input"/>并且<see cref="typeConstraint"/>为<see cref="TypeConstraint.Inherited"/>时可用</param>
/// <param name="onCreation">Called on the list on creation. Use this if you want to customize the created ReorderableList</param> /// <param name="onCreation">Called on the list on creation. Use this if you want to customize the created ReorderableList</param>
public static void DynamicPortList(string fieldName, Type type, SerializedObject serializedObject, XNode.NodePort.IO io, XNode.Node.ConnectionType connectionType = XNode.Node.ConnectionType.Multiple, XNode.Node.TypeConstraint typeConstraint = XNode.Node.TypeConstraint.None, Action<ReorderableList> onCreation = null) { public static void DynamicPortList(string fieldName, Type type, SerializedObject serializedObject, XNode.NodePort.IO io, XNode.Node.ConnectionType connectionType = XNode.Node.ConnectionType.Multiple, XNode.Node.TypeConstraint typeConstraint = XNode.Node.TypeConstraint.None,Type inputTypeConstraintBaseType = null, Action<ReorderableList> onCreation = null) {
XNode.Node node = serializedObject.targetObject as XNode.Node; XNode.Node node = serializedObject.targetObject as XNode.Node;
var indexedPorts = node.DynamicPorts.Select(x => { var indexedPorts = node.DynamicPorts.Select(x => {
@ -300,7 +301,7 @@ namespace XNodeEditor {
// If a ReorderableList isn't cached for this array, do so. // If a ReorderableList isn't cached for this array, do so.
if (list == null) { if (list == null) {
SerializedProperty arrayData = serializedObject.FindProperty(fieldName); SerializedProperty arrayData = serializedObject.FindProperty(fieldName);
list = CreateReorderableList(fieldName, dynamicPorts, arrayData, type, serializedObject, io, connectionType, typeConstraint, onCreation); list = CreateReorderableList(fieldName, dynamicPorts, arrayData, type, serializedObject, io, connectionType, typeConstraint, inputTypeConstraintBaseType,onCreation);
if (reorderableListCache.TryGetValue(serializedObject.targetObject, out rlc)) rlc.Add(fieldName, list); if (reorderableListCache.TryGetValue(serializedObject.targetObject, out rlc)) rlc.Add(fieldName, list);
else reorderableListCache.Add(serializedObject.targetObject, new Dictionary<string, ReorderableList>() { { fieldName, list } }); else reorderableListCache.Add(serializedObject.targetObject, new Dictionary<string, ReorderableList>() { { fieldName, list } });
} }
@ -308,7 +309,7 @@ namespace XNodeEditor {
list.DoLayoutList(); list.DoLayoutList();
} }
private static ReorderableList CreateReorderableList(string fieldName, List<XNode.NodePort> dynamicPorts, SerializedProperty arrayData, Type type, SerializedObject serializedObject, XNode.NodePort.IO io, XNode.Node.ConnectionType connectionType, XNode.Node.TypeConstraint typeConstraint, Action<ReorderableList> onCreation) { private static ReorderableList CreateReorderableList(string fieldName, List<XNode.NodePort> dynamicPorts, SerializedProperty arrayData, Type type, SerializedObject serializedObject, XNode.NodePort.IO io, XNode.Node.ConnectionType connectionType, XNode.Node.TypeConstraint typeConstraint,Type inputTypeConstraintBaseType, Action<ReorderableList> onCreation) {
bool hasArrayData = arrayData != null && arrayData.isArray; bool hasArrayData = arrayData != null && arrayData.isArray;
XNode.Node node = serializedObject.targetObject as XNode.Node; XNode.Node node = serializedObject.targetObject as XNode.Node;
ReorderableList list = new ReorderableList(dynamicPorts, null, true, true, true, true); ReorderableList list = new ReorderableList(dynamicPorts, null, true, true, true, true);
@ -398,7 +399,7 @@ namespace XNodeEditor {
while (node.HasPort(newName)) newName = fieldName + " " + (++i); while (node.HasPort(newName)) newName = fieldName + " " + (++i);
if (io == XNode.NodePort.IO.Output) node.AddDynamicOutput(type, connectionType, XNode.Node.TypeConstraint.None, newName); if (io == XNode.NodePort.IO.Output) node.AddDynamicOutput(type, connectionType, XNode.Node.TypeConstraint.None, newName);
else node.AddDynamicInput(type, connectionType, typeConstraint, newName); else node.AddDynamicInput(type, connectionType, typeConstraint,inputTypeConstraintBaseType, newName);
serializedObject.Update(); serializedObject.Update();
EditorUtility.SetDirty(node); EditorUtility.SetDirty(node);
if (hasArrayData) { if (hasArrayData) {
@ -472,7 +473,7 @@ namespace XNodeEditor {
int i = 0; int i = 0;
while (node.HasPort(newName)) newName = arrayData.name + " " + (++i); while (node.HasPort(newName)) newName = arrayData.name + " " + (++i);
if (io == XNode.NodePort.IO.Output) node.AddDynamicOutput(type, connectionType, typeConstraint,newName); if (io == XNode.NodePort.IO.Output) node.AddDynamicOutput(type, connectionType, typeConstraint,newName);
else node.AddDynamicInput(type, connectionType, typeConstraint, newName); else node.AddDynamicInput(type, connectionType, typeConstraint, inputTypeConstraintBaseType,newName);
EditorUtility.SetDirty(node); EditorUtility.SetDirty(node);
dynamicPortCount++; dynamicPortCount++;
} }

View File

@ -73,7 +73,7 @@ namespace XNode {
[Obsolete("Use AddDynamicPort instead")] [Obsolete("Use AddDynamicPort instead")]
private NodePort AddInstancePort(Type type, NodePort.IO direction, Node.ConnectionType connectionType = Node.ConnectionType.Multiple, Node.TypeConstraint typeConstraint = TypeConstraint.None, string fieldName = null) { private NodePort AddInstancePort(Type type, NodePort.IO direction, Node.ConnectionType connectionType = Node.ConnectionType.Multiple, Node.TypeConstraint typeConstraint = TypeConstraint.None, string fieldName = null) {
return AddDynamicPort(type, direction, connectionType, typeConstraint, fieldName); return AddDynamicPort(type, direction, connectionType, typeConstraint, null,fieldName);
} }
[Obsolete("Use RemoveDynamicPort instead")] [Obsolete("Use RemoveDynamicPort instead")]
@ -138,21 +138,21 @@ namespace XNode {
/// <summary> Convenience function. </summary> /// <summary> Convenience function. </summary>
/// <seealso cref="AddInstancePort"/> /// <seealso cref="AddInstancePort"/>
/// <seealso cref="AddInstanceOutput"/> /// <seealso cref="AddInstanceOutput"/>
public NodePort AddDynamicInput(Type type, Node.ConnectionType connectionType = Node.ConnectionType.Multiple, Node.TypeConstraint typeConstraint = TypeConstraint.None, string fieldName = null) { public NodePort AddDynamicInput(Type type, Node.ConnectionType connectionType = Node.ConnectionType.Multiple, Node.TypeConstraint typeConstraint = TypeConstraint.None,Type baseType = null, string fieldName = null) {
return AddDynamicPort(type, NodePort.IO.Input, connectionType, typeConstraint, fieldName); return AddDynamicPort(type, NodePort.IO.Input, connectionType, typeConstraint,baseType, fieldName);
} }
/// <summary> Convenience function. </summary> /// <summary> Convenience function. </summary>
/// <seealso cref="AddInstancePort"/> /// <seealso cref="AddInstancePort"/>
/// <seealso cref="AddInstanceInput"/> /// <seealso cref="AddInstanceInput"/>
public NodePort AddDynamicOutput(Type type, Node.ConnectionType connectionType = Node.ConnectionType.Multiple, Node.TypeConstraint typeConstraint = TypeConstraint.None, string fieldName = null) { public NodePort AddDynamicOutput(Type type, Node.ConnectionType connectionType = Node.ConnectionType.Multiple, Node.TypeConstraint typeConstraint = TypeConstraint.None, string fieldName = null) {
return AddDynamicPort(type, NodePort.IO.Output, connectionType, typeConstraint, fieldName); return AddDynamicPort(type, NodePort.IO.Output, connectionType, typeConstraint, null,fieldName);
} }
/// <summary> Add a dynamic, serialized port to this node. </summary> /// <summary> Add a dynamic, serialized port to this node. </summary>
/// <seealso cref="AddDynamicInput"/> /// <seealso cref="AddDynamicInput"/>
/// <seealso cref="AddDynamicOutput"/> /// <seealso cref="AddDynamicOutput"/>
private NodePort AddDynamicPort(Type type, NodePort.IO direction, Node.ConnectionType connectionType = Node.ConnectionType.Multiple, Node.TypeConstraint typeConstraint = TypeConstraint.None, string fieldName = null) { private NodePort AddDynamicPort(Type type, NodePort.IO direction, Node.ConnectionType connectionType = Node.ConnectionType.Multiple, Node.TypeConstraint typeConstraint = TypeConstraint.None,Type baseType = null, string fieldName = null) {
if (fieldName == null) { if (fieldName == null) {
fieldName = "dynamicInput_0"; fieldName = "dynamicInput_0";
int i = 0; int i = 0;
@ -161,7 +161,7 @@ namespace XNode {
Debug.LogWarning("Port '" + fieldName + "' already exists in " + name, this); Debug.LogWarning("Port '" + fieldName + "' already exists in " + name, this);
return ports[fieldName]; return ports[fieldName];
} }
NodePort port = new NodePort(fieldName, type, direction, connectionType, typeConstraint, this); NodePort port = new NodePort(fieldName, type, direction, connectionType, typeConstraint,baseType, this);
ports.Add(fieldName, port); ports.Add(fieldName, port);
return port; return port;
} }
@ -268,17 +268,20 @@ namespace XNode {
public bool instancePortList { get { return dynamicPortList; } set { dynamicPortList = value; } } public bool instancePortList { get { return dynamicPortList; } set { dynamicPortList = value; } }
public bool dynamicPortList; public bool dynamicPortList;
public TypeConstraint typeConstraint; public TypeConstraint typeConstraint;
public Type BaseType { get; }
/// <summary> Mark a serializable field as an input port. You can access this through <see cref="GetInputPort(string)"/> </summary> /// <summary> Mark a serializable field as an input port. You can access this through <see cref="GetInputPort(string)"/> </summary>
/// <param name="baseType">指定更准确的父类类型,只有当<see cref="typeConstraint"/>参数为<seealso cref="TypeConstraint.Inherited"/>才可用</param>
/// <param name="backingValue">Should we display the backing value for this port as an editor field? </param> /// <param name="backingValue">Should we display the backing value for this port as an editor field? </param>
/// <param name="connectionType">Should we allow multiple connections? </param> /// <param name="connectionType">Should we allow multiple connections? </param>
/// <param name="typeConstraint">Constrains which input connections can be made to this port </param> /// <param name="typeConstraint">Constrains which input connections can be made to this port </param>
/// <param name="dynamicPortList">If true, will display a reorderable list of inputs instead of a single port. Will automatically add and display values for lists and arrays </param> /// <param name="dynamicPortList">If true, will display a reorderable list of inputs instead of a single port. Will automatically add and display values for lists and arrays </param>
public InputAttribute(ShowBackingValue backingValue = ShowBackingValue.Unconnected, ConnectionType connectionType = ConnectionType.Multiple, TypeConstraint typeConstraint = TypeConstraint.None, bool dynamicPortList = false) { public InputAttribute(ShowBackingValue backingValue = ShowBackingValue.Unconnected, ConnectionType connectionType = ConnectionType.Multiple, TypeConstraint typeConstraint = TypeConstraint.None,Type baseType = null, bool dynamicPortList = false) {
this.backingValue = backingValue; this.backingValue = backingValue;
this.connectionType = connectionType; this.connectionType = connectionType;
this.dynamicPortList = dynamicPortList; this.dynamicPortList = dynamicPortList;
this.typeConstraint = typeConstraint; this.typeConstraint = typeConstraint;
BaseType = baseType;
} }
} }

View File

@ -36,7 +36,12 @@ namespace XNode {
if (!port.IsDynamic && port.direction == staticPort.direction) removedPorts.Add(port.fieldName, port.GetConnections()); if (!port.IsDynamic && port.direction == staticPort.direction) removedPorts.Add(port.fieldName, port.GetConnections());
port.ClearConnections(); port.ClearConnections();
ports.Remove(port.fieldName); ports.Remove(port.fieldName);
} else port.ValueType = staticPort.ValueType; }
else
{
port.ValueType = staticPort.ValueType;
port.TypeConstraintBaseType = staticPort.TypeConstraintBaseType;
}
} }
// If port doesn't exist anymore, remove it // If port doesn't exist anymore, remove it
else if (port.IsStatic) { else if (port.IsStatic) {

View File

@ -42,11 +42,28 @@ namespace XNode {
if (value != null) _typeQualifiedName = value.AssemblyQualifiedName; if (value != null) _typeQualifiedName = value.AssemblyQualifiedName;
} }
} }
private Type valueType;
public Type TypeConstraintBaseType {
get {
if (_typeConstraintBaseType == null && !string.IsNullOrEmpty(_typeConstraintBaseTypeQualifiedName))
_typeConstraintBaseType = Type.GetType(_typeConstraintBaseTypeQualifiedName, false);
return _typeConstraintBaseType;
}
set {
_typeConstraintBaseType = value;
if (value != null)
{
_typeConstraintBaseTypeQualifiedName = value.AssemblyQualifiedName;
}
}
}
private Type valueType;
private Type _typeConstraintBaseType;
[SerializeField] private string _fieldName; [SerializeField] private string _fieldName;
[SerializeField] private Node _node; [SerializeField] private Node _node;
[SerializeField] private string _typeQualifiedName; [SerializeField] private string _typeQualifiedName;
[SerializeField] private string _typeConstraintBaseTypeQualifiedName;
[SerializeField] private List<PortConnection> connections = new List<PortConnection>(); [SerializeField] private List<PortConnection> connections = new List<PortConnection>();
[SerializeField] private IO _direction; [SerializeField] private IO _direction;
[SerializeField] private Node.ConnectionType _connectionType; [SerializeField] private Node.ConnectionType _connectionType;
@ -64,6 +81,7 @@ namespace XNode {
_direction = IO.Input; _direction = IO.Input;
_connectionType = (attribs[i] as Node.InputAttribute).connectionType; _connectionType = (attribs[i] as Node.InputAttribute).connectionType;
_typeConstraint = (attribs[i] as Node.InputAttribute).typeConstraint; _typeConstraint = (attribs[i] as Node.InputAttribute).typeConstraint;
TypeConstraintBaseType = (attribs[i] as Node.InputAttribute).BaseType;
} else if (attribs[i] is Node.OutputAttribute) { } else if (attribs[i] is Node.OutputAttribute) {
_direction = IO.Output; _direction = IO.Output;
_connectionType = (attribs[i] as Node.OutputAttribute).connectionType; _connectionType = (attribs[i] as Node.OutputAttribute).connectionType;
@ -84,9 +102,10 @@ namespace XNode {
} }
/// <summary> Construct a dynamic port. Dynamic ports are not forgotten on reimport, and is ideal for runtime-created ports. </summary> /// <summary> Construct a dynamic port. Dynamic ports are not forgotten on reimport, and is ideal for runtime-created ports. </summary>
public NodePort(string fieldName, Type type, IO direction, Node.ConnectionType connectionType, Node.TypeConstraint typeConstraint, Node node) { public NodePort(string fieldName, Type type, IO direction, Node.ConnectionType connectionType, Node.TypeConstraint typeConstraint,Type baseType, Node node) {
_fieldName = fieldName; _fieldName = fieldName;
this.ValueType = type; this.ValueType = type;
TypeConstraintBaseType = baseType;
_direction = direction; _direction = direction;
_node = node; _node = node;
_dynamic = true; _dynamic = true;
@ -257,7 +276,20 @@ namespace XNode {
// If there isn't one of each, they can't connect // If there isn't one of each, they can't connect
if (input == null || output == null) return false; if (input == null || output == null) return false;
// Check input type constraints // Check input type constraints
if (input.typeConstraint == XNode.Node.TypeConstraint.Inherited && !input.ValueType.IsAssignableFrom(output.ValueType)) return false; if (input.typeConstraint == XNode.Node.TypeConstraint.Inherited)
{
//无法分配,失败
if (!input.ValueType.IsAssignableFrom(output.ValueType))
{
return false;
}
//如果存在指定基类,同时无法分配,失败
if (input.TypeConstraintBaseType != null && !input.TypeConstraintBaseType.IsAssignableFrom(output.ValueType))
{
return false;
}
}
if (input.typeConstraint == XNode.Node.TypeConstraint.Strict && input.ValueType != output.ValueType) return false; if (input.typeConstraint == XNode.Node.TypeConstraint.Strict && input.ValueType != output.ValueType) return false;
// Check output type constraints // Check output type constraints
if (output.typeConstraint == XNode.Node.TypeConstraint.Inherited && !output.ValueType.IsAssignableFrom(input.ValueType)) return false; if (output.typeConstraint == XNode.Node.TypeConstraint.Inherited && !output.ValueType.IsAssignableFrom(input.ValueType)) return false;