- Added Input/Output compatibility check to event based nodes

- Removed a huge chunk of compatibility checking code out of CMItem
This commit is contained in:
Nils Hausfeld
2023-09-30 13:45:21 +02:00
parent 35f641955b
commit 719efc4a99
2 changed files with 41 additions and 74 deletions

View File

@@ -2223,6 +2223,43 @@ namespace FlaxEditor.Surface.Archetypes
base.OnDestroy();
}
internal static bool IsInputCompatible(NodeArchetype nodeArch, ScriptType outputType, ConnectionsHint hint)
{
// Event based nodes always have a pulse input, so it's always compatible with void
if (outputType.IsVoid)
return true;
var eventName = (string)nodeArch.DefaultValues[1];
var eventType = TypeUtils.GetType((string)nodeArch.DefaultValues[0]);
var member = eventType.GetMember(eventName, MemberTypes.Event, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
if (member && SurfaceUtils.IsValidVisualScriptEvent(member))
{
if (!member.IsStatic)
{
if (VisjectSurface.FullCastCheck(eventType, outputType, hint))
return true;
}
}
return false;
}
internal static bool IsOutputCompatible(NodeArchetype nodeArch, ScriptType inputType, ConnectionsHint hint)
{
// Event based nodes always have a pulse output, so it's always compatible with void
if (inputType.IsVoid)
return true;
var eventName = (string)nodeArch.DefaultValues[1];
var eventType = TypeUtils.GetType((string)nodeArch.DefaultValues[0]);
var member = eventType.GetMember(eventName, MemberTypes.Event, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
if (member && SurfaceUtils.IsValidVisualScriptEvent(member))
{
if (VisjectSurface.FullCastCheck(member.ValueType, inputType, hint))
return true;
}
return false;
}
}
private sealed class BindEventNode : EventBaseNode
@@ -2402,6 +2439,8 @@ namespace FlaxEditor.Surface.Archetypes
{
TypeID = 9,
Create = (id, context, arch, groupArch) => new BindEventNode(id, context, arch, groupArch),
IsInputCompatible = EventBaseNode.IsInputCompatible,
IsOutputCompatible = EventBaseNode.IsOutputCompatible,
Title = string.Empty,
Flags = NodeFlags.VisualScriptGraph | NodeFlags.NoSpawnViaGUI,
Size = new Float2(260, 60),
@@ -2424,6 +2463,8 @@ namespace FlaxEditor.Surface.Archetypes
{
TypeID = 10,
Create = (id, context, arch, groupArch) => new UnbindEventNode(id, context, arch, groupArch),
IsInputCompatible = EventBaseNode.IsInputCompatible,
IsOutputCompatible = EventBaseNode.IsOutputCompatible,
Title = string.Empty,
Flags = NodeFlags.VisualScriptGraph | NodeFlags.NoSpawnViaGUI,
Size = new Float2(260, 60),

View File

@@ -109,7 +109,6 @@ namespace FlaxEditor.Surface.ContextMenu
return false;
bool isCompatible = false;
if (startBox.IsOutput && _archetype.IsInputCompatible != null)
{
isCompatible |= _archetype.IsInputCompatible.Invoke(_archetype, startBox.CurrentType, _archetype.ConnectionsHints);
@@ -124,79 +123,6 @@ namespace FlaxEditor.Surface.ContextMenu
isCompatible = CheckElementsCompatibility(startBox);
}
// Check compatibility based on the archetype tag or name. This handles custom groups and items, mainly function nodes for visual scripting
/*if (_archetype.NodeTypeHint is NodeTypeHint.FunctionNode)
{
ScriptMemberInfo memberInfo = ScriptMemberInfo.Null;
// Check if the archetype tag already has a member info otherwise try to fetch it via the archetype type and name
// Only really the InvokeMethod Nodes have a member info in their tag
if (_archetype.Tag is ScriptMemberInfo tagInfo)
{
memberInfo = tagInfo;
}
else if(_archetype.DefaultValues is { Length: > 1 }) // We have to check since VisualScriptFunctionNode and ReturnNode don't have a name and type
{
var eventName = (string)_archetype.DefaultValues[1];
var eventType = TypeUtils.GetType((string)_archetype.DefaultValues[0]);
memberInfo = eventType.GetMember(eventName, System.Reflection.MemberTypes.Event,
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.Static |
System.Reflection.BindingFlags.Instance);
}
if (memberInfo != ScriptMemberInfo.Null)
{
isCompatible |= CheckMemberInfoCompatibility(startBox, memberInfo);
}
}*/
/*else */
return isCompatible;
}
private bool CheckMemberInfoCompatibility(Box startBox, ScriptMemberInfo info)
{
bool isCompatible = false;
// Box was dragged from an impulse port and the member info can be invoked so it is compatible
if (startBox.CurrentType.IsVoid && info.ValueType.IsVoid)
{
isCompatible = true;
}
else
{
// When the startBox is output we only need to check the input parameters
if (startBox.IsOutput && !info.IsField)
{
var parameters = info.GetParameters();
ScriptType outType = startBox.CurrentType;
// non static members have an instance input parameter
if (!info.IsStatic)
{
var scriptType = info.DeclaringType;
isCompatible |= VisjectSurface.FullCastCheck(scriptType, outType, _archetype.ConnectionsHints);
}
// We ignore event members here since they only have output parameters, which are currently not declared as such
if (!info.IsEvent)
{
for (int i = 0; i < parameters.Length; i++)
{
ScriptType inType = parameters[i].Type;
isCompatible |= VisjectSurface.FullCastCheck(inType, outType, _archetype.ConnectionsHints);
}
}
}
else
{
// When the startBox is input we only have to check the output type of the method
ScriptType inType = startBox.CurrentType;
ScriptType outType = info.ValueType;
isCompatible |= VisjectSurface.FullCastCheck(inType, outType, _archetype.ConnectionsHints);
}
}
return isCompatible;
}