void UK2Node_Variable::CreatePinForSelf() { const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>(); // Create the self pin if (!K2Schema->FindSelfPin(*this, EGPD_Input)) { // Do not create a self pin for locally scoped variables if( !VariableReference.IsLocalScope() ) { bool bSelfTarget = VariableReference.IsSelfContext() && (ESelfContextInfo::NotSelfContext != SelfContextInfo); UClass* MemberParentClass = VariableReference.GetMemberParentClass(GetBlueprintClassFromNode()); UClass* TargetClass = MemberParentClass; // Self Target pins should always make the class be the owning class of the property, // so if the node is from a Macro Blueprint, it will hook up as self in any placed Blueprint if(bSelfTarget) { if(UProperty* Property = VariableReference.ResolveMember<UProperty>(GetBlueprintClassFromNode())) { TargetClass = Property->GetOwnerClass()->GetAuthoritativeClass(); } else { TargetClass = GetBlueprint()->SkeletonGeneratedClass->GetAuthoritativeClass(); } } else if(MemberParentClass && MemberParentClass->ClassGeneratedBy) { TargetClass = MemberParentClass->GetAuthoritativeClass(); } UEdGraphPin* TargetPin = CreatePin(EGPD_Input, K2Schema->PC_Object, TEXT(""), TargetClass, false, false, K2Schema->PN_Self); TargetPin->PinFriendlyName = LOCTEXT("Target", "Target"); if (bSelfTarget) { TargetPin->bHidden = true; // don't show in 'self' context } } } else { //@TODO: Check that the self pin types match! } }
FText UK2Node_CallFunctionOnMember::GetFunctionContextString() const { UClass* MemberVarClass = MemberVariableToCallOn.GetMemberParentClass(GetBlueprintClassFromNode()); FText CallFunctionClassName = (MemberVarClass != NULL) ? MemberVarClass->GetDisplayNameText() : FText::GetEmpty(); FFormatNamedArguments Args; Args.Add(TEXT("TargetName"), CallFunctionClassName); Args.Add(TEXT("MemberVariableName"), FText::FromName(MemberVariableToCallOn.GetMemberName())); return FText::Format(LOCTEXT("CallFunctionOnMemberDifferentContext", "Target is {TargetName} ({MemberVariableName})"), Args); }
FName UK2Node_Variable::GetCornerIcon() const { const UProperty* VariableProperty = VariableReference.ResolveMember<UProperty>(GetBlueprintClassFromNode()); if (VariableProperty && VariableProperty->HasAllPropertyFlags(CPF_Net)) { return TEXT("Graph.Replication.Replicated"); } return Super::GetCornerIcon(); }
void UK2Node_Variable::CheckForErrors(const UEdGraphSchema_K2* Schema, FCompilerResultsLog& MessageLog) { if(!VariableReference.IsSelfContext() && VariableReference.GetMemberParentClass(GetBlueprintClassFromNode()) != NULL) { // Check to see if we're not a self context, if we have a valid context. It may have been purged because of a dead execution chain UEdGraphPin* ContextPin = Schema->FindSelfPin(*this, EGPD_Input); if((ContextPin != NULL) && (ContextPin->LinkedTo.Num() == 0) && (ContextPin->DefaultObject == NULL)) { MessageLog.Error(*LOCTEXT("VarNodeError_InvalidVarTarget", "Variable node @@ uses an invalid target. It may depend on a node that is not connected to the execution chain, and got purged.").ToString(), this); } } }
void UK2Node_Variable::AutowireNewNode(UEdGraphPin* FromPin) { const UEdGraphSchema_K2* K2Schema = CastChecked<UEdGraphSchema_K2>(GetSchema()); // Do some auto-connection if (FromPin != NULL) { bool bConnected = false; if(FromPin->Direction == EGPD_Output) { // If the source pin has a valid PinSubCategoryObject, we might be doing BP Comms, so check if it is a class if(FromPin->PinType.PinSubCategoryObject.IsValid() && FromPin->PinType.PinSubCategoryObject->IsA(UClass::StaticClass())) { UProperty* VariableProperty = VariableReference.ResolveMember<UProperty>(GetBlueprintClassFromNode()); if(VariableProperty) { UClass* PropertyOwner = VariableProperty->GetOwnerClass(); if (PropertyOwner != nullptr) { PropertyOwner = PropertyOwner->GetAuthoritativeClass(); } // BP Comms is highly likely at this point, if the source pin's type is a child of the variable's owner class, let's conform the "Target" pin if(FromPin->PinType.PinSubCategoryObject == PropertyOwner || dynamic_cast<UClass*>(FromPin->PinType.PinSubCategoryObject.Get())->IsChildOf(PropertyOwner)) { UEdGraphPin* TargetPin = FindPin(K2Schema->PN_Self); if (TargetPin) { TargetPin->PinType.PinSubCategoryObject = PropertyOwner; if(K2Schema->TryCreateConnection(FromPin, TargetPin)) { bConnected = true; // Setup the VariableReference correctly since it may no longer be a self member VariableReference.SetFromField<UProperty>(GetPropertyForVariable(), false); TargetPin->bHidden = false; FromPin->GetOwningNode()->NodeConnectionListChanged(); this->NodeConnectionListChanged(); } } } } } } if(!bConnected) { Super::AutowireNewNode(FromPin); } } }
FName UK2Node_Variable::GetPaletteIcon(FLinearColor& ColorOut) const { FName ReturnIconName; if(VariableReference.IsLocalScope()) { ReturnIconName = GetVariableIconAndColor(VariableReference.GetMemberScope(GetBlueprintClassFromNode()), GetVarName(), ColorOut); } else { ReturnIconName = GetVariableIconAndColor(GetVariableSourceClass(), GetVarName(), ColorOut); } return ReturnIconName; }
bool UK2Node_CallFunctionOnMember::HasExternalDependencies(TArray<class UStruct*>* OptionalOutput) const { const UBlueprint* SourceBlueprint = GetBlueprint(); auto VarProperty = MemberVariableToCallOn.ResolveMember<UProperty>(GetBlueprintClassFromNode()); UClass* SourceClass = VarProperty ? VarProperty->GetOwnerClass() : nullptr; const bool bResult = (SourceClass != NULL) && (SourceClass->ClassGeneratedBy != SourceBlueprint); if (bResult && OptionalOutput) { OptionalOutput->AddUnique(SourceClass); } const bool bSuperResult = Super::HasExternalDependencies(OptionalOutput); return bSuperResult || bResult; }
bool UK2Node_Variable::CanPasteHere(const UEdGraph* TargetGraph) const { // Do not allow pasting of variables in BPs that cannot handle them if ( FBlueprintEditorUtils::FindBlueprintForGraph(TargetGraph)->BlueprintType == BPTYPE_MacroLibrary && VariableReference.IsSelfContext() ) { // Self variables must be from a parent class to the macro BP if(UProperty* Property = VariableReference.ResolveMember<UProperty>(GetBlueprintClassFromNode())) { const UClass* CurrentClass = GetBlueprint()->SkeletonGeneratedClass->GetAuthoritativeClass(); const UClass* PropertyClass = Property->GetOwnerClass()->GetAuthoritativeClass(); const bool bIsChildOf = CurrentClass->IsChildOf(PropertyClass); return bIsChildOf; } return false; } return true; }
FText UK2Node_CallParentFunction::GetNodeTitle(ENodeTitleType::Type TitleType) const { UFunction* Function = FunctionReference.ResolveMember<UFunction>(GetBlueprintClassFromNode()); FText FunctionName; if (Function) { FunctionName = GetUserFacingFunctionName( Function ); } else if ( GEditor && GetDefault<UEditorStyleSettings>()->bShowFriendlyNames ) { FunctionName = FText::FromString(FName::NameToDisplayString(FunctionReference.GetMemberName().ToString(), false)); } FFormatNamedArguments Args; Args.Add(TEXT("FunctionName"), FunctionName); return FText::Format( LOCTEXT( "CallSuperFunction", "Parent: {FunctionName}" ), Args); }
void UK2Node_CommutativeAssociativeBinaryOperator::AllocateDefaultPins() { Super::AllocateDefaultPins(); const UFunction* Function = GetTargetFunction(); if(NULL != Function) { check(Function->HasAnyFunctionFlags(FUNC_BlueprintPure)); #if DO_CHECK ensure(FindOutPin()); ensure((FindSelfPin() ? 4 : 3) == Pins.Num()); { //VALIDATION const FEdGraphPinType InputType = GetType(); int32 NativeInputPinsNum = 0; for (int32 PinIt = 0; PinIt < Pins.Num(); PinIt++) { const UEdGraphPin* Pin = Pins[PinIt]; if (Pin != FindSelfPin()) { ensure(InputType == Pin->PinType); NativeInputPinsNum += (EEdGraphPinDirection::EGPD_Input == Pin->Direction) ? 1 : 0; } } ensure(BinaryOperatorInputsNum == NativeInputPinsNum); } #endif // DO_CHECK for (int32 i = 0; i < NumAdditionalInputs; ++i) { AddInputPinInner(i); } } else { const UClass* FunctionParentClass = FunctionReference.GetMemberParentClass(GetBlueprintClassFromNode()); Message_Error(FString::Printf( *LOCTEXT("NoFunction_Error", "CommutativeAssociativeBinaryOperator has no function: '%s' class: '%s'").ToString(), *FunctionReference.GetMemberName().ToString(), (FunctionParentClass ? *FunctionParentClass->GetName() : TEXT("None")) )); } }
FText UK2Node_VariableGet::GetNodeTitle(ENodeTitleType::Type TitleType) const { // If there is only one variable being read, the title can be made the variable name FString OutputPinName; int32 NumOutputsFound = 0; for (int32 PinIndex = 0; PinIndex < Pins.Num(); ++PinIndex) { UEdGraphPin* Pin = Pins[PinIndex]; // The following code is to attempt to log info related to UE-19729 if (TitleType == ENodeTitleType::ListView) { if (UEdGraph* Graph = Cast<UEdGraph>(GetOuter())) { FString VariableName = GetVarNameString(); FString BlueprintPath = FBlueprintEditorUtils::FindBlueprintForGraph(Graph)->GetPathName(); FString SetupStyle = bIsPureGet? TEXT("pure") : TEXT("validated"); FString VariableResolves = (VariableReference.ResolveMember<UProperty>(GetBlueprintClassFromNode()) != nullptr)? TEXT("resolves") : TEXT("does not resolve"); checkf(Pin, TEXT("Get node for variable '%s' in Blueprint '%s' which is setup as %s and has %d pins. Variable %s"), *VariableName, *BlueprintPath, *SetupStyle, Pins.Num(), *VariableResolves); } } if (Pin->Direction == EGPD_Output) { ++NumOutputsFound; OutputPinName = Pin->PinName; } } if (NumOutputsFound != 1) { return LOCTEXT("Get", "Get"); } else if (CachedNodeTitle.IsOutOfDate(this)) { FFormatNamedArguments Args; Args.Add(TEXT("PinName"), FText::FromString(OutputPinName)); // FText::Format() is slow, so we cache this to save on performance CachedNodeTitle.SetCachedText(FText::Format(LOCTEXT("GetPinName", "Get {PinName}"), Args), this); } return CachedNodeTitle; }
FText UK2Node_Variable::GetToolTipHeading() const { FText Heading = Super::GetToolTipHeading(); UProperty const* VariableProperty = VariableReference.ResolveMember<UProperty>(GetBlueprintClassFromNode()); if (VariableProperty && VariableProperty->HasAllPropertyFlags(CPF_Net)) { FText ReplicatedTag = LOCTEXT("ReplicatedVar", "Replicated"); if (Heading.IsEmpty()) { Heading = ReplicatedTag; } else { Heading = FText::Format(FText::FromString("{0}\n{1}"), ReplicatedTag, Heading); } } return Heading; }
FBPVariableDescription const* UK2Node_Variable::GetBlueprintVarDescription() const { FName const& VarName = VariableReference.GetMemberName(); UStruct const* VariableScope = VariableReference.GetMemberScope(GetBlueprintClassFromNode()); bool const bIsLocalVariable = (VariableScope != nullptr); if (bIsLocalVariable) { return FBlueprintEditorUtils::FindLocalVariable(GetBlueprint(), VariableScope, VarName); } else if (UProperty const* VarProperty = GetPropertyForVariable()) { UClass const* SourceClass = VarProperty->GetOwnerClass(); UBlueprint const* SourceBlueprint = (SourceClass != nullptr) ? Cast<UBlueprint>(SourceClass->ClassGeneratedBy) : nullptr; if (SourceBlueprint != nullptr) { int32 const VarIndex = FBlueprintEditorUtils::FindNewVariableIndex(SourceBlueprint, VarName); return &SourceBlueprint->NewVariables[VarIndex]; } } return nullptr; }
UProperty* UK2Node_Variable::GetPropertyForVariable() const { const FName VarName = GetVarName(); UEdGraphPin* VariablePin = FindPin(GetVarNameString()); UProperty* VariableProperty = VariableReference.ResolveMember<UProperty>(GetBlueprintClassFromNode()); // if the variable has been deprecated, don't use it if(VariableProperty != NULL) { if (VariableProperty->HasAllPropertyFlags(CPF_Deprecated)) { VariableProperty = NULL; } // If the variable has been remapped update the pin else if (VariablePin && VarName != GetVarName()) { VariablePin->PinName = GetVarNameString(); } } return VariableProperty; }
UClass* UK2Node_Variable::GetVariableSourceClass() const { UClass* Result = VariableReference.GetMemberParentClass(GetBlueprintClassFromNode()); return Result; }
void UK2Node_Variable::PostPasteNode() { Super::PostPasteNode(); UBlueprint* Blueprint = GetBlueprint(); bool bInvalidateVariable = false; if (VariableReference.ResolveMember<UProperty>(Blueprint) == nullptr) { bInvalidateVariable = true; } else if (VariableReference.IsLocalScope()) { // Local scoped variables should always validate whether they are being placed in the same graph as their scope // ResolveMember will not return nullptr when the graph changes but the Blueprint remains the same. UEdGraph* ScopeGraph = FBlueprintEditorUtils::FindScopeGraph(Blueprint, VariableReference.GetMemberScope(GetBlueprintClassFromNode())); if(ScopeGraph != GetGraph()) { bInvalidateVariable = true; } } if (bInvalidateVariable) { // This invalidates the local scope VariableReference.InvalidateScope(); // If the current graph is a Function graph, look to see if there is a compatible local variable (same name) if (GetGraph()->GetSchema()->GetGraphType(GetGraph()) == GT_Function) { FBPVariableDescription* VariableDescription = FBlueprintEditorUtils::FindLocalVariable(Blueprint, GetGraph(), VariableReference.GetMemberName()); if(VariableDescription) { VariableReference.SetLocalMember(VariableReference.GetMemberName(), GetGraph()->GetName(), VariableReference.GetMemberGuid()); } } // If no variable was found, ResolveMember should automatically find a member variable with the same name in the current Blueprint and hook up to it as expected } }
UEdGraphPin* UK2Node_CallFunctionOnMember::CreateSelfPin(const UFunction* Function) { const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>(); UEdGraphPin* SelfPin = NULL; if (MemberVariableToCallOn.IsSelfContext()) { // This means the function is defined within the blueprint, so the pin should be a true "self" pin SelfPin = CreatePin(EGPD_Input, K2Schema->PC_Object, K2Schema->PSC_Self, NULL, false, false, K2Schema->PN_Self); } else { // This means that the function is declared in an external class, and should reference that class SelfPin = CreatePin(EGPD_Input, K2Schema->PC_Object, TEXT(""), MemberVariableToCallOn.GetMemberParentClass(GetBlueprintClassFromNode()), false, false, K2Schema->PN_Self); } check(SelfPin != NULL); return SelfPin; }