// Copyright Epic Games, Inc. All Rights Reserved. #include "K2Node_FunctionTerminator.h" #include "UObject/UnrealType.h" #include "UObject/FrameworkObjectVersion.h" #include "GraphEditorSettings.h" #include "EdGraphSchema_K2.h" #include "Kismet2/BlueprintEditorUtils.h" #include "Kismet2/CompilerResultsLog.h" #define LOCTEXT_NAMESPACE "K2Node" UK2Node_FunctionTerminator::UK2Node_FunctionTerminator(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { } void UK2Node_FunctionTerminator::Serialize(FArchive& Ar) { Super::Serialize(Ar); Ar.UsingCustomVersion(FFrameworkObjectVersion::GUID); if (Ar.IsLoading()) { if (Ar.CustomVer(FFrameworkObjectVersion::GUID) < FFrameworkObjectVersion::FunctionTerminatorNodesUseMemberReference) { FunctionReference.SetExternalMember(SignatureName_DEPRECATED, SignatureClass_DEPRECATED); } } } FLinearColor UK2Node_FunctionTerminator::GetNodeTitleColor() const { return GetDefault()->FunctionTerminatorNodeTitleColor; } FName UK2Node_FunctionTerminator::CreateUniquePinName(FName InSourcePinName) const { const UFunction* FoundFunction = FFunctionFromNodeHelper::FunctionFromNode(this); FName ResultName = InSourcePinName; int UniqueNum = 0; // Prevent the unique name from being the same as another of the UFunction's properties while(FindPin(ResultName) || FindFProperty(FoundFunction, ResultName) != nullptr) { ResultName = *FString::Printf(TEXT("%s%d"), *InSourcePinName.ToString(), ++UniqueNum); } return ResultName; } bool UK2Node_FunctionTerminator::CanCreateUserDefinedPin(const FEdGraphPinType& InPinType, EEdGraphPinDirection InDesiredDirection, FText& OutErrorMessage) { const bool bIsNodeEditable = IsEditable(); // Make sure that if this is an exec node we are allowed one. if (bIsNodeEditable && InPinType.PinCategory == UEdGraphSchema_K2::PC_Exec && !CanModifyExecutionWires()) { OutErrorMessage = LOCTEXT("MultipleExecPinError", "Cannot support more exec pins!"); return false; } else if (!bIsNodeEditable) { OutErrorMessage = LOCTEXT("NotEditableError", "Cannot edit this node!"); } return bIsNodeEditable; } bool UK2Node_FunctionTerminator::HasExternalDependencies(TArray* OptionalOutput) const { const UBlueprint* SourceBlueprint = GetBlueprint(); UClass* SourceClass = FunctionReference.GetMemberParentClass(GetBlueprintClassFromNode()); bool bResult = (SourceClass != nullptr) && (SourceClass->ClassGeneratedBy != SourceBlueprint); if (bResult && OptionalOutput) { OptionalOutput->AddUnique(SourceClass); } // All structures, that are required for the BP compilation, should be gathered for (auto Pin : Pins) { UStruct* DepStruct = Pin ? Cast(Pin->PinType.PinSubCategoryObject.Get()) : nullptr; UClass* DepClass = Cast(DepStruct); if (DepClass && (DepClass->ClassGeneratedBy == SourceBlueprint)) { //Don't include self continue; } if (DepStruct && !DepStruct->IsNative()) { if (OptionalOutput) { OptionalOutput->AddUnique(DepStruct); } bResult = true; } } const bool bSuperResult = Super::HasExternalDependencies(OptionalOutput); return bSuperResult || bResult; } void UK2Node_FunctionTerminator::PostPasteNode() { Super::PostPasteNode(); UEdGraph* Graph = GetGraph(); if (ensure(Graph)) { FunctionReference.SetExternalMember(Graph->GetFName(), nullptr); } } void UK2Node_FunctionTerminator::PromoteFromInterfaceOverride(bool bIsPrimaryTerminator) { // Remove the signature class, that is not relevant. FunctionReference.SetSelfMember(FunctionReference.GetMemberName()); // For every pin that has been defined, make it a user defined pin if we can for (UEdGraphPin* const Pin : Pins) { if (Pin->PinType.PinCategory != UEdGraphSchema_K2::PC_Exec && !UserDefinedPinExists(Pin->PinName)) { TSharedPtr NewPinInfo = MakeShareable(new FUserPinInfo()); NewPinInfo->PinName = Pin->PinName; NewPinInfo->PinType = Pin->PinType; NewPinInfo->DesiredPinDirection = Pin->Direction; UserDefinedPins.Add(NewPinInfo); } } const UEdGraphSchema_K2* Schema = GetDefault(); Schema->ReconstructNode(*this, true); } UFunction* UK2Node_FunctionTerminator::FindSignatureFunction() const { UClass* FoundClass = GetBlueprintClassFromNode(); UFunction* FoundFunction = FunctionReference.ResolveMember(FoundClass); if (!FoundFunction && FoundClass && GetOuter()) { // The resolve will fail if this is a locally-created function, so search using the event graph name FoundFunction = FindUField(FoundClass, *GetOuter()->GetName()); } return FoundFunction; } void UK2Node_FunctionTerminator::ValidateNodeDuringCompilation(FCompilerResultsLog& MessageLog) const { Super::ValidateNodeDuringCompilation(MessageLog); for (UEdGraphPin* Pin : Pins) { if (Pin && Pin->PinType.bIsWeakPointer && !Pin->PinType.IsContainer()) { const FString ErrorString = FText::Format( LOCTEXT("WeakPtrNotSupportedErrorFmt", "Weak pointers are not supported as function parameters. Pin '{0}' @@"), FText::FromString(Pin->GetName()) ).ToString(); MessageLog.Error(*ErrorString, this); } } } #undef LOCTEXT_NAMESPACE