FText UK2Node_Message::GetNodeTitle(ENodeTitleType::Type TitleType) const { FText NodeName; if (UFunction* Function = GetTargetFunction()) { if (!CachedNodeTitles.IsTitleCached(TitleType)) { FText NodeNameText = FText::FromString(UK2Node_CallFunction::GetUserFacingFunctionName(Function)); if (TitleType == ENodeTitleType::MenuTitle) { // FText::Format() is slow, so we cache this to save on performance CachedNodeTitles.SetCachedTitle(TitleType, FText::Format(LOCTEXT("ListTitle", "{0} (Message)"), NodeNameText)); } else { FFormatNamedArguments Args; Args.Add(TEXT("NodeName"), NodeNameText); Args.Add(TEXT("OuterClassName"), FText::FromString(Function->GetOuterUClass()->GetName())); FText NodeTitle = FText::Format(NSLOCTEXT("K2Node", "CallInterfaceContext", "{NodeName}\nUsing Interface {OuterClassName}"), Args); // FText::Format() is slow, so we cache this to save on performance CachedNodeTitles.SetCachedTitle(TitleType, NodeTitle); } } } else { return NSLOCTEXT("K2Node", "InvalidMessageNode", "Invalid Message Node"); } return CachedNodeTitles.GetCachedTitle(TitleType); }
void UK2Node_CallArrayFunction::GetArrayPins(TArray< FArrayPropertyPinCombo >& OutArrayPinInfo ) const { OutArrayPinInfo.Empty(); UFunction* TargetFunction = GetTargetFunction(); check(TargetFunction); FString ArrayPointerMetaData = TargetFunction->GetMetaData(FBlueprintMetadata::MD_ArrayParam); TArray<FString> ArrayPinComboNames; ArrayPointerMetaData.ParseIntoArray(ArrayPinComboNames, TEXT(","), true); for(auto Iter = ArrayPinComboNames.CreateConstIterator(); Iter; ++Iter) { TArray<FString> 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); } } }
void UK2Node_AddComponent::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { Super::ExpandNode(CompilerContext, SourceGraph); auto TransformPin = GetRelativeTransformPin(); if (TransformPin && !TransformPin->LinkedTo.Num()) { FString DefaultValue; // Try and find the template and get relative transform from it UEdGraphPin* TemplateNamePin = GetTemplateNamePinChecked(); const FString TemplateName = TemplateNamePin->DefaultValue; check(CompilerContext.Blueprint); USceneComponent* SceneCompTemplate = Cast<USceneComponent>(CompilerContext.Blueprint->FindTemplateByName(FName(*TemplateName))); if (SceneCompTemplate) { FTransform TemplateTransform = FTransform(SceneCompTemplate->RelativeRotation, SceneCompTemplate->RelativeLocation, SceneCompTemplate->RelativeScale3D); DefaultValue = TemplateTransform.ToString(); } auto ValuePin = InnerHandleAutoCreateRef(this, TransformPin, CompilerContext, SourceGraph, !DefaultValue.IsEmpty()); if (ValuePin) { ValuePin->DefaultValue = DefaultValue; } } if (bHasExposedVariable) { static FString ObjectParamName = FString(TEXT("Object")); static FString ValueParamName = FString(TEXT("Value")); static FString PropertyNameParamName = FString(TEXT("PropertyName")); UK2Node_AddComponent* NewNode = CompilerContext.SpawnIntermediateNode<UK2Node_AddComponent>(this, SourceGraph); NewNode->SetFromFunction(GetTargetFunction()); NewNode->AllocateDefaultPinsWithoutExposedVariables(); // function parameters const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>(); CompilerContext.MovePinLinksToIntermediate(*FindPin(K2Schema->PN_Self), *NewNode->FindPin(K2Schema->PN_Self)); CompilerContext.MovePinLinksToIntermediate(*GetTemplateNamePinChecked(), *NewNode->GetTemplateNamePinChecked()); CompilerContext.MovePinLinksToIntermediate(*GetRelativeTransformPin(), *NewNode->GetRelativeTransformPin()); CompilerContext.MovePinLinksToIntermediate(*GetManualAttachmentPin(), *NewNode->GetManualAttachmentPin()); UEdGraphPin* ReturnPin = NewNode->GetReturnValuePin(); UEdGraphPin* OriginalReturnPin = GetReturnValuePin(); check((NULL != ReturnPin) && (NULL != OriginalReturnPin)); ReturnPin->PinType = OriginalReturnPin->PinType; CompilerContext.MovePinLinksToIntermediate(*OriginalReturnPin, *ReturnPin); // exec in CompilerContext.MovePinLinksToIntermediate(*GetExecPin(), *NewNode->GetExecPin()); UEdGraphPin* LastThen = FKismetCompilerUtilities::GenerateAssignmentNodes( CompilerContext, SourceGraph, NewNode, this, ReturnPin, GetSpawnedType() ); CompilerContext.MovePinLinksToIntermediate(*GetThenPin(), *LastThen); BreakAllNodeLinks(); } }
void UK2Node_CommutativeAssociativeBinaryOperator::ExpandNode(FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { Super::ExpandNode(CompilerContext, SourceGraph); if (NumAdditionalInputs > 0) { const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema(); UEdGraphPin* LastOutPin = NULL; const UFunction* const Function = GetTargetFunction(); const UEdGraphPin* SrcOutPin = FindOutPin(); const UEdGraphPin* SrcSelfPin = FindSelfPin(); UEdGraphPin* SrcFirstInput = GetInputPin(0); check(SrcFirstInput); for(int32 PinIndex = 0; PinIndex < Pins.Num(); PinIndex++) { UEdGraphPin* CurrentPin = Pins[PinIndex]; if( (CurrentPin == SrcFirstInput) || (CurrentPin == SrcOutPin) || (SrcSelfPin == CurrentPin) ) { continue; } UK2Node_CommutativeAssociativeBinaryOperator* NewOperator = SourceGraph->CreateBlankNode<UK2Node_CommutativeAssociativeBinaryOperator>(); NewOperator->SetFromFunction(Function); NewOperator->AllocateDefaultPins(); CompilerContext.MessageLog.NotifyIntermediateObjectCreation(NewOperator, this); UEdGraphPin* NewOperatorInputA = NewOperator->GetInputPin(0); check(NewOperatorInputA); if(LastOutPin) { Schema->TryCreateConnection(LastOutPin, NewOperatorInputA); } else { // handle first created node (SrcFirstInput is skipped, and has no own node). CompilerContext.MovePinLinksToIntermediate(*SrcFirstInput, *NewOperatorInputA); } UEdGraphPin* NewOperatorInputB = NewOperator->GetInputPin(1); check(NewOperatorInputB); CompilerContext.MovePinLinksToIntermediate(*CurrentPin, *NewOperatorInputB); LastOutPin = NewOperator->FindOutPin(); check(LastOutPin); } UEdGraphPin* TrueOutPin = FindOutPin(); check(TrueOutPin); CompilerContext.MovePinLinksToIntermediate(*TrueOutPin, *LastOutPin); BreakAllNodeLinks(); } }
void UK2Node_Message::AllocateDefaultPins() { UFunction* MessageNodeFunction = GetTargetFunction(); // since we have branching logic in ExpandNode(), this has to be an impure // node with exec pins // // @TODO: make it so we can have impure message nodes using a custom // FNodeHandlingFunctor, instead of ExpandNode() if (MessageNodeFunction && MessageNodeFunction->HasAnyFunctionFlags(FUNC_BlueprintPure)) { // Input - Execution Pin CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, TEXT(""), NULL, false, false, UEdGraphSchema_K2::PN_Execute); // Output - Execution Pin CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, TEXT(""), NULL, false, false, UEdGraphSchema_K2::PN_Then); } Super::AllocateDefaultPins(); }
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")) )); } }
void UK2Node_CallArrayFunction::GetArrayTypeDependentPins(TArray<UEdGraphPin*>& OutPins) const { OutPins.Empty(); UFunction* TargetFunction = GetTargetFunction(); check(TargetFunction); const FString DependentPinMetaData = TargetFunction->GetMetaData(FBlueprintMetadata::MD_ArrayDependentParam); TArray<FString> TypeDependentPinNames; DependentPinMetaData.ParseIntoArray(TypeDependentPinNames, TEXT(","), true); for(TArray<UEdGraphPin*>::TConstIterator it(Pins); it; ++it) { UEdGraphPin* CurrentPin = *it; int32 ItemIndex = 0; if( CurrentPin && TypeDependentPinNames.Find(CurrentPin->PinName, ItemIndex) ) { OutPins.Add(CurrentPin); } } }
void UK2Node_Message::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { Super::ExpandNode(CompilerContext, SourceGraph); const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema(); UEdGraphPin* ExecPin = Schema->FindExecutionPin(*this, EGPD_Input); const bool bExecPinConnected = ExecPin && (ExecPin->LinkedTo.Num() > 0); UEdGraphPin* ThenPin = Schema->FindExecutionPin(*this, EGPD_Output); const bool bThenPinConnected = ThenPin && (ThenPin->LinkedTo.Num() > 0); // Skip ourselves if our exec isn't wired up if (bExecPinConnected) { // Make sure our interface is valid if (FunctionReference.GetMemberParentClass(this) == NULL) { CompilerContext.MessageLog.Error(*FString::Printf(*LOCTEXT("MessageNodeInvalid_Error", "Message node @@ has an invalid interface.").ToString()), this); return; } UFunction* MessageNodeFunction = GetTargetFunction(); if (MessageNodeFunction == NULL) { //@TODO: Why do this here in teh compiler, it's already done on AllocateDefaultPins() during on-load node reconstruction MessageNodeFunction = Cast<UFunction>(UK2Node::FindRemappedField(FunctionReference.GetMemberParentClass(this), FunctionReference.GetMemberName())); } if (MessageNodeFunction == NULL) { CompilerContext.MessageLog.Error(*FString::Printf(*LOCTEXT("MessageNodeInvalidFunction_Error", "Unable to find function with name %s for Message node @@.").ToString(), *(FunctionReference.GetMemberName().ToString())), this); return; } // Check to make sure we have a target UEdGraphPin* MessageSelfPin = Schema->FindSelfPin(*this, EGPD_Input); if( !MessageSelfPin || MessageSelfPin->LinkedTo.Num() == 0 ) { CompilerContext.MessageLog.Error(*FString::Printf(*LOCTEXT("MessageNodeSelfPin_Error", "Message node @@ must have a valid target or reference to self.").ToString()), this); return; } // First, create an internal cast-to-interface node UK2Node_DynamicCast* CastToInterfaceNode = CompilerContext.SpawnIntermediateNode<UK2Node_DynamicCast>(this, SourceGraph); CastToInterfaceNode->TargetType = MessageNodeFunction->GetOuterUClass(); CastToInterfaceNode->SetPurity(false); CastToInterfaceNode->AllocateDefaultPins(); UEdGraphPin* CastToInterfaceResultPin = CastToInterfaceNode->GetCastResultPin(); if( !CastToInterfaceResultPin ) { CompilerContext.MessageLog.Error(*LOCTEXT("InvalidInterfaceClass_Error", "Node @@ has an invalid target interface class").ToString(), this); return; } CastToInterfaceResultPin->PinType.PinSubCategoryObject = *CastToInterfaceNode->TargetType; if (ExecPin != nullptr) { UEdGraphPin* CastExecInput = CastToInterfaceNode->GetExecPin(); check(CastExecInput != nullptr); // Wire up the connections CompilerContext.MovePinLinksToIntermediate(*ExecPin, *CastExecInput); } UEdGraphPin* CastToInterfaceSourceObjectPin = CastToInterfaceNode->GetCastSourcePin(); CompilerContext.MovePinLinksToIntermediate(*MessageSelfPin, *CastToInterfaceSourceObjectPin); // Next, create the function call node UK2Node_CallFunction* FunctionCallNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); FunctionCallNode->bIsInterfaceCall = true; FunctionCallNode->FunctionReference = FunctionReference; FunctionCallNode->AllocateDefaultPins(); UEdGraphPin* CastToInterfaceValidPin = CastToInterfaceNode->GetValidCastPin(); check(CastToInterfaceValidPin != nullptr); UEdGraphPin* LastOutCastFaildPin = CastToInterfaceNode->GetInvalidCastPin(); check(LastOutCastFaildPin != nullptr); UEdGraphPin* LastOutCastSuccessPin = CastToInterfaceValidPin; // Wire up the connections if (UEdGraphPin* CallFunctionExecPin = Schema->FindExecutionPin(*FunctionCallNode, EGPD_Input)) { CastToInterfaceValidPin->MakeLinkTo(CallFunctionExecPin); LastOutCastSuccessPin = Schema->FindExecutionPin(*FunctionCallNode, EGPD_Output); } // Self pin UEdGraphPin* FunctionCallSelfPin = Schema->FindSelfPin(*FunctionCallNode, EGPD_Input); CastToInterfaceResultPin->MakeLinkTo(FunctionCallSelfPin); UFunction* ArrayClearFunction = UKismetArrayLibrary::StaticClass()->FindFunctionByName(FName(TEXT("Array_Clear"))); check(ArrayClearFunction); bool const bIsPureFunc = Super::IsNodePure(); // Variable pins - Try to associate variable inputs to the message node with the variable inputs and outputs to the call function node for( int32 i = 0; i < Pins.Num(); i++ ) { UEdGraphPin* CurrentPin = Pins[i]; if( CurrentPin && (CurrentPin->PinType.PinCategory != Schema->PC_Exec) && (CurrentPin->PinName != Schema->PN_Self) ) { // Try to find a match for the pin on the function call node UEdGraphPin* FunctionCallPin = FunctionCallNode->FindPin(CurrentPin->PinName); if( FunctionCallPin ) { // Move pin links if the pin is connected... CompilerContext.MovePinLinksToIntermediate(*CurrentPin, *FunctionCallPin); // when cast fails all return values must be cleared. if (EEdGraphPinDirection::EGPD_Output == CurrentPin->Direction) { UEdGraphPin* VarOutPin = FunctionCallPin; if (bIsPureFunc) { // since we cannot directly use the output from the // function call node (since it is pure, and invoking // it with a null target would cause an error), we // have to use a temporary variable in it's place... UK2Node_TemporaryVariable* TempVar = CompilerContext.SpawnIntermediateNode<UK2Node_TemporaryVariable>(this, SourceGraph); TempVar->VariableType = CurrentPin->PinType; TempVar->AllocateDefaultPins(); VarOutPin = TempVar->GetVariablePin(); // nodes using the function's outputs directly, now // use this TempVar node instead CompilerContext.MovePinLinksToIntermediate(*FunctionCallPin, *VarOutPin); // on a successful cast, the temp var is filled with // the function's value, on a failed cast, the var // is filled with a default value (DefaultValueNode, // below)... this is the node for the success case: UK2Node_AssignmentStatement* AssignTempVar = CompilerContext.SpawnIntermediateNode<UK2Node_AssignmentStatement>(this, SourceGraph); AssignTempVar->AllocateDefaultPins(); // assign the output from the pure function node to // the TempVar (either way, this message node is // returning the TempVar's value, so on a successful // cast we want it to have the function's result) UEdGraphPin* ValueInPin = AssignTempVar->GetValuePin(); Schema->TryCreateConnection(FunctionCallPin, ValueInPin); AssignTempVar->PinConnectionListChanged(ValueInPin); UEdGraphPin* VarInPin = AssignTempVar->GetVariablePin(); Schema->TryCreateConnection(VarOutPin, VarInPin); AssignTempVar->PinConnectionListChanged(VarInPin); // fold this AssignTempVar node into the cast's // success execution chain Schema->TryCreateConnection(AssignTempVar->GetExecPin(), LastOutCastSuccessPin); LastOutCastSuccessPin = AssignTempVar->GetThenPin(); } UK2Node* DefaultValueNode = NULL; UEdGraphPin* DefaultValueThenPin = NULL; if (CurrentPin->PinType.bIsArray) { UK2Node_CallArrayFunction* ClearArray = CompilerContext.SpawnIntermediateNode<UK2Node_CallArrayFunction>(this, SourceGraph); DefaultValueNode = ClearArray; ClearArray->SetFromFunction(ArrayClearFunction); ClearArray->AllocateDefaultPins(); UEdGraphPin* ArrayPin = ClearArray->GetTargetArrayPin(); check(ArrayPin); Schema->TryCreateConnection(ArrayPin, VarOutPin); ClearArray->PinConnectionListChanged(ArrayPin); DefaultValueThenPin = ClearArray->GetThenPin(); } else { UK2Node_AssignmentStatement* AssignDefaultValue = CompilerContext.SpawnIntermediateNode<UK2Node_AssignmentStatement>(this, SourceGraph); DefaultValueNode = AssignDefaultValue; AssignDefaultValue->AllocateDefaultPins(); Schema->TryCreateConnection(AssignDefaultValue->GetVariablePin(), VarOutPin); AssignDefaultValue->PinConnectionListChanged(AssignDefaultValue->GetVariablePin()); Schema->SetPinDefaultValueBasedOnType(AssignDefaultValue->GetValuePin()); DefaultValueThenPin = AssignDefaultValue->GetThenPin(); } UEdGraphPin* DefaultValueExecPin = DefaultValueNode->GetExecPin(); check(DefaultValueExecPin); Schema->TryCreateConnection(DefaultValueExecPin, LastOutCastFaildPin); LastOutCastFaildPin = DefaultValueThenPin; check(LastOutCastFaildPin); } } else { UE_LOG(LogK2Compiler, Log, TEXT("%s"), *LOCTEXT("NoPinConnectionFound_Error", "Unable to find connection for pin! Check AllocateDefaultPins() for consistency!").ToString()); } } } if( bThenPinConnected ) { check(LastOutCastFaildPin != nullptr); // Failure case for the cast runs straight through to the exit CompilerContext.CopyPinLinksToIntermediate(*ThenPin, *LastOutCastFaildPin); check(LastOutCastSuccessPin != nullptr); // Copy all links from the invalid cast case above to the call function node CompilerContext.MovePinLinksToIntermediate(*ThenPin, *LastOutCastSuccessPin); } } // Break all connections to the original node, so it will be pruned BreakAllNodeLinks(); }
void UK2Node_LoadAsset::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { Super::ExpandNode(CompilerContext, SourceGraph); const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema(); check(Schema); bool bIsErrorFree = true; // Create LoadAsset function call auto CallLoadAssetNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); CallLoadAssetNode->FunctionReference.SetExternalMember(NativeFunctionName(), UKismetSystemLibrary::StaticClass()); CallLoadAssetNode->AllocateDefaultPins(); // connect to input exe { auto InputExePin = GetExecPin(); auto CallFunctionInputExePin = CallLoadAssetNode->GetExecPin(); bIsErrorFree &= InputExePin && CallFunctionInputExePin && CompilerContext.MovePinLinksToIntermediate(*InputExePin, *CallFunctionInputExePin).CanSafeConnect(); } // Create Local Variable UK2Node_TemporaryVariable* TempVarOutput = CompilerContext.SpawnInternalVariable(this, GetOutputCategory(), FString(), UObject::StaticClass(), false); // Create assign node auto AssignNode = CompilerContext.SpawnIntermediateNode<UK2Node_AssignmentStatement>(this, SourceGraph); AssignNode->AllocateDefaultPins(); auto LoadedObjectVariablePin = TempVarOutput->GetVariablePin(); // connect local variable to assign node { auto AssignLHSPPin = AssignNode->GetVariablePin(); bIsErrorFree &= AssignLHSPPin && LoadedObjectVariablePin && Schema->TryCreateConnection(AssignLHSPPin, LoadedObjectVariablePin); } // connect local variable to output { auto OutputObjectPinPin = FindPin(GetOutputPinName()); bIsErrorFree &= LoadedObjectVariablePin && OutputObjectPinPin && CompilerContext.MovePinLinksToIntermediate(*OutputObjectPinPin, *LoadedObjectVariablePin).CanSafeConnect(); } // connect assign exec input to function output { auto CallFunctionOutputExePin = CallLoadAssetNode->FindPin(Schema->PN_Then); auto AssignInputExePin = AssignNode->GetExecPin(); bIsErrorFree &= AssignInputExePin && CallFunctionOutputExePin && Schema->TryCreateConnection(AssignInputExePin, CallFunctionOutputExePin); } // connect assign exec output to output { auto OutputExePin = FindPin(Schema->PN_Then); auto AssignOutputExePin = AssignNode->GetThenPin(); bIsErrorFree &= OutputExePin && AssignOutputExePin && CompilerContext.MovePinLinksToIntermediate(*OutputExePin, *AssignOutputExePin).CanSafeConnect(); } // connect to asset { auto AssetPin = FindPin(GetInputPinName()); auto CallFunctionAssetPin = CallLoadAssetNode->FindPin(GetInputPinName()); ensure(CallFunctionAssetPin); bIsErrorFree &= AssetPin && CallFunctionAssetPin && CompilerContext.MovePinLinksToIntermediate(*AssetPin, *CallFunctionAssetPin).CanSafeConnect(); } // Create OnLoadEvent const FString DelegateOnLoadedParamName(TEXT("OnLoaded")); auto OnLoadEventNode = CompilerContext.SpawnIntermediateNode<UK2Node_CustomEvent>(this, SourceGraph); OnLoadEventNode->CustomFunctionName = *FString::Printf(TEXT("OnLoaded_%s"), *OnLoadEventNode->NodeGuid.ToString()); OnLoadEventNode->AllocateDefaultPins(); { UFunction* LoadAssetFunction = CallLoadAssetNode->GetTargetFunction(); UDelegateProperty* OnLoadDelegateProperty = LoadAssetFunction ? FindField<UDelegateProperty>(LoadAssetFunction, *DelegateOnLoadedParamName) : nullptr; UFunction* OnLoadedSignature = OnLoadDelegateProperty ? OnLoadDelegateProperty->SignatureFunction : nullptr; ensure(OnLoadedSignature); for (TFieldIterator<UProperty> PropIt(OnLoadedSignature); PropIt && (PropIt->PropertyFlags & CPF_Parm); ++PropIt) { const UProperty* Param = *PropIt; if (!Param->HasAnyPropertyFlags(CPF_OutParm) || Param->HasAnyPropertyFlags(CPF_ReferenceParm)) { FEdGraphPinType PinType; bIsErrorFree &= Schema->ConvertPropertyToPinType(Param, /*out*/ PinType); bIsErrorFree &= (NULL != OnLoadEventNode->CreateUserDefinedPin(Param->GetName(), PinType, EGPD_Output)); } } } // connect delegate { auto CallFunctionDelegatePin = CallLoadAssetNode->FindPin(DelegateOnLoadedParamName); ensure(CallFunctionDelegatePin); auto EventDelegatePin = OnLoadEventNode->FindPin(UK2Node_CustomEvent::DelegateOutputName); bIsErrorFree &= CallFunctionDelegatePin && EventDelegatePin && Schema->TryCreateConnection(CallFunctionDelegatePin, EventDelegatePin); } // connect loaded object from event to assign { auto LoadedAssetEventPin = OnLoadEventNode->FindPin(TEXT("Loaded")); ensure(LoadedAssetEventPin); auto AssignRHSPPin = AssignNode->GetValuePin(); bIsErrorFree &= AssignRHSPPin && LoadedAssetEventPin && Schema->TryCreateConnection(LoadedAssetEventPin, AssignRHSPPin); } if (!bIsErrorFree) { CompilerContext.MessageLog.Error(*LOCTEXT("InternalConnectionError", "K2Node_LoadAsset: Internal connection error. @@").ToString(), this); } BreakAllNodeLinks(); }
void UK2Node_CallFunctionOnMember::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { // This skips UK2Node_CallFunction::ExpandNode. Instead it spawns a new CallFunction node and does hookup that this is interested in, // and then that CallFunction node will get its own Expansion to handle the parent portions UK2Node::ExpandNode(CompilerContext, SourceGraph); if (CompilerContext.bIsFullCompile) { const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema(); UFunction* Function = GetTargetFunction(); // Create real 'call function' node. UK2Node_CallFunction* CallFuncNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); CallFuncNode->SetFromFunction(Function); CallFuncNode->AllocateDefaultPins(); UEdGraphPin* CallFuncSelfPin = Schema->FindSelfPin(*CallFuncNode, EGPD_Input); // Now because you can wire multiple variables to a self pin, need to iterate over each one and create a 'get var' node for each UEdGraphPin* SelfPin = Schema->FindSelfPin(*this, EGPD_Input); if(SelfPin != NULL) { if (SelfPin->LinkedTo.Num() == 0) { UK2Node_VariableGet* GetVarNode = CompilerContext.SpawnIntermediateNode<UK2Node_VariableGet>(this, SourceGraph); GetVarNode->VariableReference.SetSelfMember(MemberVariableToCallOn.GetMemberName()); GetVarNode->AllocateDefaultPins(); if (UEdGraphPin* ValuePin = GetVarNode->GetValuePin()) { ValuePin->MakeLinkTo(CallFuncSelfPin); } } else { for (int32 TargetIdx = 0; TargetIdx < SelfPin->LinkedTo.Num(); TargetIdx++) { UEdGraphPin* SourcePin = SelfPin->LinkedTo[TargetIdx]; if (SourcePin != NULL) { // Create 'get var' node to get the member UK2Node_VariableGet* GetVarNode = CompilerContext.SpawnIntermediateNode<UK2Node_VariableGet>(this, SourceGraph); GetVarNode->VariableReference = MemberVariableToCallOn; GetVarNode->AllocateDefaultPins(); UEdGraphPin* VarNodeSelfPin = Schema->FindSelfPin(*GetVarNode, EGPD_Input); if (VarNodeSelfPin != NULL) { VarNodeSelfPin->MakeLinkTo(SourcePin); UEdGraphPin* ValuePin = GetVarNode->GetValuePin(); ValuePin->MakeLinkTo(CallFuncSelfPin); } else { // Failed to find the member to call on for this expansion, so warn about it CompilerContext.MessageLog.Warning(*LOCTEXT("CallFunctionOnInvalidMember_Warning", "Function node @@ called on invalid target member.").ToString(), this); } } } } } // Now move the rest of the connections (including exec connections...) for(int32 SrcPinIdx=0; SrcPinIdx<Pins.Num(); SrcPinIdx++) { UEdGraphPin* SrcPin = Pins[SrcPinIdx]; if(SrcPin != NULL && SrcPin != SelfPin) // check its not the self pin { UEdGraphPin* DestPin = CallFuncNode->FindPin(SrcPin->PinName); if(DestPin != NULL) { CompilerContext.MovePinLinksToIntermediate(*SrcPin, *DestPin); // Source node is assumed to be owner... } } } // Finally, break any remaining links on the 'call func on member' node BreakAllNodeLinks(); } }