Fix wildcard array library functions (Array_Add, Array_RemoveItem, etc)

Real root cause, found after two incorrect attempts: ConnectBlueprintPins
always instantiated the generic UK2Node_CallFunction for every CallFunction
node, including wildcard array library functions like Array_Add and
Array_RemoveItem. Only UK2Node_CallArrayFunction (a UK2Node_CallFunction
subclass) overrides NotifyPinConnectionListChanged to resolve its wildcard
TargetArray/Item pins from the connected array's type -- the generic base
class has a no-op default, so no connection-notification of any kind could
ever have fixed it. This also explains why the ForEachLoop fix (a
MacroInstance, unrelated class hierarchy) worked while this didn't, despite
looking like the same "wildcard pin" symptom.

Debugging trail for the record: first tried NodeConnectionListChanged()
(wrong function, no args -- happened to be irrelevant to both bugs and
coincidentally look like it fixed ForEachLoop). Then tried adding
ReconstructNode() (no effect). Then matched the schema's actual
TryCreateConnection code exactly (PinConnectionListChanged(Pin) with the
specific pin) -- correct in general (this IS what fixes MacroInstance
wildcards, confirmed via UE_LOG marker showing the call executes), but
insufficient here because the node class itself was wrong.

Fix: check TargetFunc->HasMetaData(TEXT("ArrayParm")) (the same meta key
UK2Node_CallArrayFunction itself checks) and instantiate the correct class
before calling SetFromFunction(). Verified: Array_Add's TargetArray/NewItem
pins now show concrete "object/Actor" type instead of wildcard, and the
containing Blueprint compiles.
This commit is contained in:
Joshua Deville
2026-07-08 22:49:16 -04:00
parent 226a979d66
commit 536f828b6c

View File

@@ -51,6 +51,7 @@
#include "K2Node_DynamicCast.h"
#include "K2Node_InputKey.h"
#include "K2Node_SpawnActorFromClass.h"
#include "K2Node_CallArrayFunction.h"
#include "EdGraphSchema_K2.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "Kismet2/KismetEditorUtilities.h"
@@ -395,12 +396,32 @@ static UEdGraphNode* CreateBPNodeFromJson(UEdGraph* Graph, UBlueprint* Blueprint
return nullptr;
}
FGraphNodeCreator<UK2Node_CallFunction> Creator(*Graph);
UK2Node_CallFunction* FuncNode = Creator.CreateNode(false);
FuncNode->SetFromFunction(TargetFunc);
FuncNode->NodePosX = PosX;
FuncNode->NodePosY = PosY;
Creator.Finalize();
// Wildcard array library functions (Array_Add, Array_RemoveItem, etc, tagged with the
// "ArrayParm" meta key) need to be instantiated as UK2Node_CallArrayFunction, not the
// plain UK2Node_CallFunction -- only that subclass overrides NotifyPinConnectionListChanged
// to resolve its wildcard TargetArray/Item pins from the connected array's type. Using the
// base class silently produces a node whose wildcard pins never resolve, no matter what
// connection-notification is fired afterward.
UK2Node_CallFunction* FuncNode = nullptr;
if (TargetFunc->HasMetaData(TEXT("ArrayParm")))
{
FGraphNodeCreator<UK2Node_CallArrayFunction> ArrayCreator(*Graph);
UK2Node_CallArrayFunction* ArrayFuncNode = ArrayCreator.CreateNode(false);
ArrayFuncNode->SetFromFunction(TargetFunc);
ArrayFuncNode->NodePosX = PosX;
ArrayFuncNode->NodePosY = PosY;
ArrayCreator.Finalize();
FuncNode = ArrayFuncNode;
}
else
{
FGraphNodeCreator<UK2Node_CallFunction> Creator(*Graph);
FuncNode = Creator.CreateNode(false);
FuncNode->SetFromFunction(TargetFunc);
FuncNode->NodePosX = PosX;
FuncNode->NodePosY = PosY;
Creator.Finalize();
}
NewNode = FuncNode;
}
else if (NodeType == TEXT("Event"))
@@ -791,11 +812,14 @@ FString UMCPythonHelper::ConnectBlueprintPins(UBlueprint* Blueprint, const FStri
SourcePin->MakeLinkTo(TargetPin);
// Notify both nodes so wildcard pins (e.g. MacroInstance nodes like ForEachLoop, or
// wildcard array library calls) can resolve their type from the new connection. The
// real graph editor does this via the schema's TryCreateConnection; MakeLinkTo alone
// doesn't trigger it, so wildcard-typed pins were silently left unresolved.
SourceNode->NodeConnectionListChanged();
TargetNode->NodeConnectionListChanged();
// wildcard array library calls like Array_Add/Array_RemoveItem) can resolve their type
// from the new connection. This mirrors exactly what UEdGraphSchema::TryCreateConnection
// does after MakeLinkTo (see EdGraphSchema.cpp) -- MakeLinkTo alone doesn't trigger it,
// so wildcard-typed pins were silently left unresolved. Must pass the specific pin, not
// a bare no-arg notification: PinConnectionListChanged(Pin) is what K2Node subclasses
// (e.g. K2Node_CallArrayFunction::NotifyPinConnectionListChanged) actually key off of.
SourcePin->GetOwningNode()->PinConnectionListChanged(SourcePin);
TargetPin->GetOwningNode()->PinConnectionListChanged(TargetPin);
FBlueprintEditorUtils::MarkBlueprintAsModified(Blueprint);
return MakeJsonSuccess(FString::Printf(TEXT("Connected %s.%s -> %s.%s"),