From 536f828b6cdf36dea7595000a051f31868d35dbf Mon Sep 17 00:00:00 2001 From: Joshua Deville Date: Wed, 8 Jul 2026 22:49:16 -0400 Subject: [PATCH] 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. --- .../UnrealMCPython/Private/MCPythonHelper.cpp | 46 ++++++++++++++----- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/Plugins/UnrealMCPython/Source/UnrealMCPython/Private/MCPythonHelper.cpp b/Plugins/UnrealMCPython/Source/UnrealMCPython/Private/MCPythonHelper.cpp index d08f410..6bb59a8 100644 --- a/Plugins/UnrealMCPython/Source/UnrealMCPython/Private/MCPythonHelper.cpp +++ b/Plugins/UnrealMCPython/Source/UnrealMCPython/Private/MCPythonHelper.cpp @@ -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 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 ArrayCreator(*Graph); + UK2Node_CallArrayFunction* ArrayFuncNode = ArrayCreator.CreateNode(false); + ArrayFuncNode->SetFromFunction(TargetFunc); + ArrayFuncNode->NodePosX = PosX; + ArrayFuncNode->NodePosY = PosY; + ArrayCreator.Finalize(); + FuncNode = ArrayFuncNode; + } + else + { + FGraphNodeCreator 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"),