void UK2Node_VariableGet::Serialize(FArchive& Ar) { // The following code is to attempt to log info related to UE-19729 if (Ar.IsSaving() && !Ar.IsTransacting()) { if (UEdGraph* Graph = Cast<UEdGraph>(GetOuter())) { if (UBlueprint* Blueprint = FBlueprintEditorUtils::FindBlueprintForGraph(Graph)) { if (!Blueprint->bBeingCompiled) { FString VariableName = GetVarNameString(); FString BlueprintPath = Blueprint->GetPathName(); FString SetupStyle = bIsPureGet? TEXT("pure") : TEXT("validated"); UE_LOG(LogBlueprintUserMessages, Log, TEXT("Serialization for Get node for variable '%s' in Blueprint '%s' which is setup as %s"), *VariableName, *BlueprintPath, *SetupStyle); // The following line may spur the crash noted in UE-19729 and will confirm that the crash happens before the FiB gather. GetNodeTitle(ENodeTitleType::ListView); } } } } Super::Serialize(Ar); }
void UK2Node_VariableGet::CreateNonPurePins(TArray<UEdGraphPin*>* InOldPinsPtr) { const UEdGraphSchema_K2* K2Schema = Cast<UEdGraphSchema_K2>(GetSchema()); check(K2Schema != nullptr); if (!K2Schema->DoesGraphSupportImpureFunctions(GetGraph())) { bIsPureGet = true; } if (!bIsPureGet) { FEdGraphPinType PinType; UProperty* VariableProperty = GetPropertyForVariable(); // We need the pin's type, to both see if it's an array and if it is of the correct types to remain an impure node if (VariableProperty) { K2Schema->ConvertPropertyToPinType(GetPropertyForVariable(), PinType); } // If there is no property and we are given some old pins to look at, find the old value pin and use the type there // This allows nodes to be pasted into other BPs without access to the property else if(InOldPinsPtr) { // find old variable pin and use the type. const FString PinName = GetVarNameString(); for(auto Iter = InOldPinsPtr->CreateConstIterator(); Iter; ++Iter) { if(const UEdGraphPin* Pin = *Iter) { if(PinName == Pin->PinName) { PinType = Pin->PinType; break; } } } } if (IsValidTypeForNonPure(PinType)) { // Input - Execution Pin CreatePin(EGPD_Input, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Execute); // Output - Execution Pins UEdGraphPin* ValidPin = CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Then); ValidPin->PinFriendlyName = LOCTEXT("Valid", "Is Valid"); UEdGraphPin* InvalidPin = CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Else); InvalidPin->PinFriendlyName = LOCTEXT("Invalid", "Is Not Valid"); } else { bIsPureGet = true; } } }
FText UK2Node_StructMemberGet::GetNodeTitle(ENodeTitleType::Type TitleType) const { if (CachedNodeTitle.IsOutOfDate(this)) { FFormatNamedArguments Args; Args.Add(TEXT("VariableName"), FText::FromString(GetVarNameString())); // FText::Format() is slow, so we cache this to save on performance CachedNodeTitle.SetCachedText(FText::Format(LOCTEXT("GetMembersInVariable", "Get members in {VariableName}"), Args), this); } return CachedNodeTitle; }
FText UK2Node_StructMemberGet::GetTooltipText() const { if (CachedTooltip.IsOutOfDate(this)) { FFormatNamedArguments Args; Args.Add(TEXT("VariableName"), FText::FromString(GetVarNameString())); // FText::Format() is slow, so we cache this to save on performance CachedTooltip.SetCachedText(FText::Format(LOCTEXT("K2Node_StructMemberGet_Tooltip", "Get member variables of {VariableName}"), Args), this); } return CachedTooltip; }
UProperty* UK2Node_Variable::GetPropertyForVariable() const { const FName VarName = GetVarName(); UEdGraphPin* VariablePin = FindPin(GetVarNameString()); UProperty* VariableProperty = nullptr; // Need to look at parent Blueprint's skeleton classes to see if the variable property can resolve there. UClass* CurrentGeneratedClass = GetBlueprint()->GeneratedClass; while(CurrentGeneratedClass && VariableProperty == nullptr) { if(UBlueprint* CurrentBlueprint = Cast<UBlueprint>(CurrentGeneratedClass->ClassGeneratedBy)) { VariableProperty = VariableReference.ResolveMember<UProperty>(CurrentBlueprint->SkeletonGeneratedClass); CurrentGeneratedClass = CurrentBlueprint->ParentClass; } else { break; } } // 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; }
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; }
bool UK2Node_Variable::CreatePinForVariable(EEdGraphPinDirection Direction, FString InPinName/* = FString()*/) { const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>(); UProperty* VariableProperty = GetPropertyForVariable(); // favor the skeleton property if possible (in case the property type has // been changed, and not yet compiled). if (!VariableReference.IsSelfContext()) { UClass* VariableClass = VariableReference.GetMemberParentClass(GetBlueprint()->GeneratedClass); if (UBlueprintGeneratedClass* BpClassOwner = Cast<UBlueprintGeneratedClass>(VariableClass)) { // this variable could currently only be a part of some skeleton // class (the blueprint has not be compiled with it yet), so let's // check the skeleton class as well, see if we can pull pin data // from there... UBlueprint* VariableBlueprint = CastChecked<UBlueprint>(BpClassOwner->ClassGeneratedBy, ECastCheckedType::NullAllowed); if (VariableBlueprint) { if (UProperty* SkelProperty = FindField<UProperty>(VariableBlueprint->SkeletonGeneratedClass, VariableReference.GetMemberName())) { VariableProperty = SkelProperty; } } } } if (VariableProperty != NULL) { const FString PinName = InPinName.IsEmpty()? GetVarNameString() : InPinName; // Create the pin UEdGraphPin* VariablePin = CreatePin(Direction, TEXT(""), TEXT(""), NULL, false, false, PinName); K2Schema->ConvertPropertyToPinType(VariableProperty, /*out*/ VariablePin->PinType); K2Schema->SetPinDefaultValueBasedOnType(VariablePin); } else { if (!VariableReference.IsLocalScope()) { Message_Warn(*FString::Printf(TEXT("CreatePinForVariable: '%s' variable not found. Base class was probably changed."), *GetVarNameString())); } return false; } return true; }
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; }
bool UK2Node_Variable::RecreatePinForVariable(EEdGraphPinDirection Direction, TArray<UEdGraphPin*>& OldPins, FString InPinName/* = FString()*/) { // probably the node was pasted to a blueprint without the variable // we don't want to beak any connection, so the pin will be recreated from old one, but compiler will throw error // find old variable pin const UEdGraphPin* OldVariablePin = NULL; const FString PinName = InPinName.IsEmpty()? GetVarNameString() : InPinName; for(auto Iter = OldPins.CreateConstIterator(); Iter; ++Iter) { if(const UEdGraphPin* Pin = *Iter) { if(PinName == Pin->PinName) { OldVariablePin = Pin; break; } } } if(NULL != OldVariablePin) { // create new pin from old one UEdGraphPin* VariablePin = CreatePin(Direction, TEXT(""), TEXT(""), NULL, false, false, PinName); VariablePin->PinType = OldVariablePin->PinType; const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>(); K2Schema->SetPinDefaultValueBasedOnType(VariablePin); Message_Note(*FString::Printf(TEXT("Pin for variable '%s' recreated, but the variable is missing."), *PinName)); return true; } else { Message_Warn(*FString::Printf(TEXT("RecreatePinForVariable: '%s' pin not found"), *PinName)); return false; } }
UEdGraphPin* UK2Node_Variable::GetValuePin() const { UEdGraphPin* Pin = FindPin(GetVarNameString()); check(Pin == NULL || Pin->Direction == EGPD_Output); return Pin; }