// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. #include "BlueprintGraphPrivatePCH.h" #include "K2Node_CallArrayFunction.h" UK2Node_CallArrayFunction::UK2Node_CallArrayFunction(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { } void UK2Node_CallArrayFunction::AllocateDefaultPins() { Super::AllocateDefaultPins(); const UEdGraphSchema_K2* Schema = GetDefault(); UEdGraphPin* TargetArrayPin = GetTargetArrayPin(); check(TargetArrayPin); TargetArrayPin->PinType.bIsArray = true; TargetArrayPin->PinType.bIsReference = true; TargetArrayPin->PinType.PinCategory = Schema->PC_Wildcard; TargetArrayPin->PinType.PinSubCategory = TEXT(""); TargetArrayPin->PinType.PinSubCategoryObject = NULL; TArray< FArrayPropertyPinCombo > ArrayPins; GetArrayPins(ArrayPins); for(auto Iter = ArrayPins.CreateConstIterator(); Iter; ++Iter) { if(Iter->ArrayPropPin) { Iter->ArrayPropPin->bHidden = true; Iter->ArrayPropPin->bNotConnectable = true; Iter->ArrayPropPin->bDefaultValueIsReadOnly = true; } } PropagateArrayTypeInfo(TargetArrayPin); } void UK2Node_CallArrayFunction::PostReconstructNode() { // cannot use a ranged for here, as PinConnectionListChanged() might end up // collapsing split pins (subtracting elements from Pins) for (int32 PinIndex = 0; PinIndex < Pins.Num(); ++PinIndex) { UEdGraphPin* Pin = Pins[PinIndex]; if (Pin->LinkedTo.Num() > 0) { PinConnectionListChanged(Pin); } } } void UK2Node_CallArrayFunction::NotifyPinConnectionListChanged(UEdGraphPin* Pin) { Super::NotifyPinConnectionListChanged(Pin); TArray PinsToCheck; GetArrayTypeDependentPins(PinsToCheck); for (int32 Index = 0; Index < PinsToCheck.Num(); ++Index) { UEdGraphPin* PinToCheck = PinsToCheck[Index]; if (PinToCheck->SubPins.Num() > 0) { PinsToCheck.Append(PinToCheck->SubPins); } } PinsToCheck.Add(GetTargetArrayPin()); if (PinsToCheck.Contains(Pin)) { const UEdGraphSchema_K2* Schema = GetDefault(); bool bNeedToPropagate = false; if( Pin->LinkedTo.Num() > 0 ) { if (Pin->PinType.PinCategory == Schema->PC_Wildcard) { UEdGraphPin* LinkedTo = Pin->LinkedTo[0]; check(LinkedTo); check(Pin->PinType.bIsArray == LinkedTo->PinType.bIsArray); Pin->PinType.PinCategory = LinkedTo->PinType.PinCategory; Pin->PinType.PinSubCategory = LinkedTo->PinType.PinSubCategory; Pin->PinType.PinSubCategoryObject = LinkedTo->PinType.PinSubCategoryObject; bNeedToPropagate = true; } } else { bNeedToPropagate = true; for (UEdGraphPin* PinToCheck : PinsToCheck) { if (PinToCheck->LinkedTo.Num() > 0) { bNeedToPropagate = false; break; } } if (bNeedToPropagate) { Pin->PinType.PinCategory = Schema->PC_Wildcard; Pin->PinType.PinSubCategory = TEXT(""); Pin->PinType.PinSubCategoryObject = NULL; } } if (bNeedToPropagate) { PropagateArrayTypeInfo(Pin); } } } UEdGraphPin* UK2Node_CallArrayFunction::GetTargetArrayPin() const { TArray< FArrayPropertyPinCombo > ArrayParmPins; GetArrayPins(ArrayParmPins); if(ArrayParmPins.Num()) { return ArrayParmPins[0].ArrayPin; } return nullptr; } void UK2Node_CallArrayFunction::GetArrayPins(TArray< FArrayPropertyPinCombo >& OutArrayPinInfo ) const { OutArrayPinInfo.Empty(); UFunction* TargetFunction = GetTargetFunction(); check(TargetFunction); FString ArrayPointerMetaData = TargetFunction->GetMetaData(FBlueprintMetadata::MD_ArrayParam); TArray ArrayPinComboNames; ArrayPointerMetaData.ParseIntoArray(ArrayPinComboNames, TEXT(","), true); for(auto Iter = ArrayPinComboNames.CreateConstIterator(); Iter; ++Iter) { TArray ArrayPinNames; Iter->ParseIntoArray(ArrayPinNames, TEXT("|"), true); FArrayPropertyPinCombo ArrayInfo; ArrayInfo.ArrayPin = FindPin(ArrayPinNames[0]); if(ArrayPinNames.Num() > 1) { ArrayInfo.ArrayPropPin = FindPin(ArrayPinNames[1]); } if(ArrayInfo.ArrayPin) { OutArrayPinInfo.Add(ArrayInfo); } } } bool UK2Node_CallArrayFunction::IsWildcardProperty(UFunction* InArrayFunction, const UProperty* InProperty) { if(InArrayFunction && InProperty) { FString ArrayPointerMetaData = InArrayFunction->GetMetaData(FBlueprintMetadata::MD_ArrayParam); TArray ArrayPinComboNames; ArrayPointerMetaData.ParseIntoArray(ArrayPinComboNames, TEXT(","), true); for(auto Iter = ArrayPinComboNames.CreateConstIterator(); Iter; ++Iter) { TArray ArrayPinNames; Iter->ParseIntoArray(ArrayPinNames, TEXT("|"), true); if(ArrayPinNames[0] == InProperty->GetName()) { return true; } } } return false; } void UK2Node_CallArrayFunction::GetArrayTypeDependentPins(TArray& OutPins) const { OutPins.Empty(); UFunction* TargetFunction = GetTargetFunction(); check(TargetFunction); const FString DependentPinMetaData = TargetFunction->GetMetaData(FBlueprintMetadata::MD_ArrayDependentParam); TArray TypeDependentPinNames; DependentPinMetaData.ParseIntoArray(TypeDependentPinNames, TEXT(","), true); for(TArray::TConstIterator it(Pins); it; ++it) { UEdGraphPin* CurrentPin = *it; int32 ItemIndex = 0; if( CurrentPin && TypeDependentPinNames.Find(CurrentPin->PinName, ItemIndex) ) { OutPins.Add(CurrentPin); } } } void UK2Node_CallArrayFunction::PropagateArrayTypeInfo(const UEdGraphPin* SourcePin) { if( SourcePin ) { const UEdGraphSchema_K2* Schema = CastChecked(GetSchema()); const FEdGraphPinType& SourcePinType = SourcePin->PinType; TArray DependentPins; GetArrayTypeDependentPins(DependentPins); DependentPins.Add(GetTargetArrayPin()); // Propagate pin type info (except for array info!) to pins with dependent types for (UEdGraphPin* CurrentPin : DependentPins) { if (CurrentPin != SourcePin) { FEdGraphPinType& CurrentPinType = CurrentPin->PinType; bool const bHasTypeMismatch = (CurrentPinType.PinCategory != SourcePinType.PinCategory) || (CurrentPinType.PinSubCategory != SourcePinType.PinSubCategory) || (CurrentPinType.PinSubCategoryObject != SourcePinType.PinSubCategoryObject); if (!bHasTypeMismatch) { continue; } if (CurrentPin->SubPins.Num() > 0) { Schema->RecombinePin(CurrentPin->SubPins[0]); } CurrentPinType.PinCategory = SourcePinType.PinCategory; CurrentPinType.PinSubCategory = SourcePinType.PinSubCategory; CurrentPinType.PinSubCategoryObject = SourcePinType.PinSubCategoryObject; // Reset default values if (!Schema->IsPinDefaultValid(CurrentPin, CurrentPin->DefaultValue, CurrentPin->DefaultObject, CurrentPin->DefaultTextValue).IsEmpty()) { CurrentPin->ResetDefaultValue(); } // Verify that all previous connections to this pin are still valid with the new type for (TArray::TIterator ConnectionIt(CurrentPin->LinkedTo); ConnectionIt; ++ConnectionIt) { UEdGraphPin* ConnectedPin = *ConnectionIt; if (!Schema->ArePinsCompatible(CurrentPin, ConnectedPin)) { CurrentPin->BreakLinkTo(ConnectedPin); } } } } } }