void UK2Node_EnumEquality::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { Super::ExpandNode(CompilerContext, SourceGraph); const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema(); // Get the enum equality node and the KismetMathLibrary function info for use when we build those nodes FName ConditionalFunctionName = ""; UClass* ConditionalFunctionClass = NULL; GetConditionalFunction(ConditionalFunctionName, &ConditionalFunctionClass); // Create the conditional node we're replacing the enum node for UK2Node_CallFunction* ConditionalNode = SourceGraph->CreateBlankNode<UK2Node_CallFunction>(); ConditionalNode->FunctionReference.SetExternalMember(ConditionalFunctionName, ConditionalFunctionClass); ConditionalNode->AllocateDefaultPins(); CompilerContext.MessageLog.NotifyIntermediateObjectCreation(ConditionalNode, this); // Rewire the enum pins to the new conditional node UEdGraphPin* LeftSideConditionalPin = ConditionalNode->FindPinChecked(TEXT("A")); UEdGraphPin* RightSideConditionalPin = ConditionalNode->FindPinChecked(TEXT("B")); UEdGraphPin* ReturnConditionalPin = ConditionalNode->FindPinChecked(Schema->PN_ReturnValue); UEdGraphPin* Input1Pin = GetInput1Pin(); UEdGraphPin* Input2Pin = GetInput2Pin(); LeftSideConditionalPin->PinType = Input1Pin->PinType; RightSideConditionalPin->PinType = Input2Pin->PinType; CompilerContext.MovePinLinksToIntermediate(*Input1Pin, *LeftSideConditionalPin); CompilerContext.MovePinLinksToIntermediate(*Input2Pin, *RightSideConditionalPin); CompilerContext.MovePinLinksToIntermediate(*GetReturnValuePin(), *ReturnConditionalPin); // Break all links to the Select node so it goes away for at scheduling time BreakAllNodeLinks(); }
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_EaseFunction::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { Super::ExpandNode(CompilerContext, SourceGraph); /** At the end of this, the UK2Node_EaseFunction will not be a part of the Blueprint, it merely handles connecting the other nodes into the Blueprint. */ UFunction* Function = UKismetMathLibrary::StaticClass()->FindFunctionByName(*EaseFunctionName); if (Function == NULL) { CompilerContext.MessageLog.Error(*LOCTEXT("InvalidFunctionName", "BaseAsyncTask: Type not supported or not initialized. @@").ToString(), this); return; } const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema(); // The call function does all the real work, each child class implementing easing for a given type provides // the name of the desired function UK2Node_CallFunction* CallFunction = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); CallFunction->SetFromFunction(Function); CallFunction->AllocateDefaultPins(); CompilerContext.MessageLog.NotifyIntermediateObjectCreation(CallFunction, this); // Move the ease function and the alpha connections from us to the call function CompilerContext.MovePinLinksToIntermediate(*FindPin(FEaseFunctionNodeHelper::GetEaseFuncPinName()), *CallFunction->FindPin(TEXT("EasingFunc"))); CompilerContext.MovePinLinksToIntermediate(*FindPin(FEaseFunctionNodeHelper::GetAlphaPinName()), *CallFunction->FindPin(TEXT("Alpha"))); // Move base connections to the call function's connections CompilerContext.MovePinLinksToIntermediate(*FindPin(FEaseFunctionNodeHelper::GetAPinName()), *CallFunction->FindPin(TEXT("A"))); CompilerContext.MovePinLinksToIntermediate(*FindPin(FEaseFunctionNodeHelper::GetBPinName()), *CallFunction->FindPin(TEXT("B"))); CompilerContext.MovePinLinksToIntermediate(*FindPin(FEaseFunctionNodeHelper::GetResultPinName()), *CallFunction->GetReturnValuePin()); // Now move the custom pins to their new locations UEdGraphPin* ShortestPathPin = FindPinChecked(FEaseFunctionNodeHelper::GetShortestPathPinName()); if (!ShortestPathPin->bHidden) { CompilerContext.MovePinLinksToIntermediate(*ShortestPathPin, *CallFunction->FindPinChecked(TEXT("bShortestPath"))); } UEdGraphPin* BlendExpPin = FindPinChecked(FEaseFunctionNodeHelper::GetBlendExpPinName()); if (!BlendExpPin->bHidden) { CompilerContext.MovePinLinksToIntermediate(*BlendExpPin, *CallFunction->FindPinChecked(FEaseFunctionNodeHelper::GetBlendExpPinName())); } UEdGraphPin* StepsPin = FindPinChecked(FEaseFunctionNodeHelper::GetStepsPinName()); if (!StepsPin->bHidden) { CompilerContext.MovePinLinksToIntermediate(*StepsPin, *CallFunction->FindPinChecked(FEaseFunctionNodeHelper::GetStepsPinName())); } // Cleanup links to ourself and we are done! 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_GenericCreateObject::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { UK2Node_CallFunction* CallCreateNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); CallCreateNode->FunctionReference.SetExternalMember(GET_FUNCTION_NAME_CHECKED(UGameplayStatics, SpawnObject), UGameplayStatics::StaticClass()); CallCreateNode->AllocateDefaultPins(); bool bSucceeded = true; //connect exe { auto SpawnExecPin = GetExecPin(); auto CallExecPin = CallCreateNode->GetExecPin(); bSucceeded &= SpawnExecPin && CallExecPin && CompilerContext.MovePinLinksToIntermediate(*SpawnExecPin, *CallExecPin).CanSafeConnect(); } //connect class { auto SpawnClassPin = GetClassPin(); auto CallClassPin = CallCreateNode->FindPin(TEXT("ObjectClass")); bSucceeded &= SpawnClassPin && CallClassPin && CompilerContext.MovePinLinksToIntermediate(*SpawnClassPin, *CallClassPin).CanSafeConnect(); } //connect outer { auto SpawnOuterPin = GetOuterPin(); auto CallOuterPin = CallCreateNode->FindPin(TEXT("Outer")); bSucceeded &= SpawnOuterPin && CallOuterPin && CompilerContext.MovePinLinksToIntermediate(*SpawnOuterPin, *CallOuterPin).CanSafeConnect(); } UEdGraphPin* CallResultPin = nullptr; //connect result { auto SpawnResultPin = GetResultPin(); CallResultPin = CallCreateNode->GetReturnValuePin(); // cast HACK. It should be safe. The only problem is native code generation. if (SpawnResultPin && CallResultPin) { CallResultPin->PinType = SpawnResultPin->PinType; } bSucceeded &= SpawnResultPin && CallResultPin && CompilerContext.MovePinLinksToIntermediate(*SpawnResultPin, *CallResultPin).CanSafeConnect(); } //assign exposed values and connect then { auto LastThen = FKismetCompilerUtilities::GenerateAssignmentNodes(CompilerContext, SourceGraph, CallCreateNode, this, CallResultPin, GetClassToSpawn()); auto SpawnNodeThen = GetThenPin(); bSucceeded &= SpawnNodeThen && LastThen && CompilerContext.MovePinLinksToIntermediate(*SpawnNodeThen, *LastThen).CanSafeConnect(); } BreakAllNodeLinks(); if (!bSucceeded) { CompilerContext.MessageLog.Error(*LOCTEXT("GenericCreateObject_Error", "ICE: GenericCreateObject error @@").ToString(), this); } }
void UGameplayTagsK2Node_MultiCompareGameplayTagContainerSingleTags::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { Super::ExpandNode(CompilerContext, SourceGraph); const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>(); // Get The input and output pins to our node UEdGraphPin* InPinSwitch = FindPin(TEXT("Gameplay Tag Container")); UEdGraphPin* InPinContainerMatchType = FindPin(TEXT("Tag Container Match Type")); UEdGraphPin* InPinTagsMatchType = FindPin(TEXT("Tags Match Type")); // For Each Pin Compare against the Tag container for (int32 Index = 0; Index < NumberOfPins; ++Index) { FString InPinName = TEXT("TagCase_") + FString::FormatAsNumber(Index); FString OutPinName = TEXT("Case_") + FString::FormatAsNumber(Index) + TEXT(" True"); UEdGraphPin* InPinCase = FindPin(InPinName); UEdGraphPin* OutPinCase = FindPin(OutPinName); // Create call function node for the Compare function HasAllMatchingGameplayTags UK2Node_CallFunction* PinCallFunction = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); const UFunction* Function = UBlueprintGameplayTagLibrary::StaticClass()->FindFunctionByName(GET_FUNCTION_NAME_CHECKED(UBlueprintGameplayTagLibrary, DoesContainerHaveTag)); PinCallFunction->SetFromFunction(Function); PinCallFunction->AllocateDefaultPins(); UEdGraphPin *TagContainerPin = PinCallFunction->FindPinChecked(FString(TEXT("TagContainer"))); CompilerContext.CopyPinLinksToIntermediate(*InPinSwitch, *TagContainerPin); UEdGraphPin *TagPin = PinCallFunction->FindPinChecked(FString(TEXT("Tag"))); CompilerContext.MovePinLinksToIntermediate(*InPinCase, *TagPin); UEdGraphPin *ContainerTagsMatchTypePin = PinCallFunction->FindPinChecked(FString(TEXT("ContainerTagsMatchType"))); CompilerContext.CopyPinLinksToIntermediate(*InPinContainerMatchType, *ContainerTagsMatchTypePin); UEdGraphPin *TagMatchTypePin = PinCallFunction->FindPinChecked(FString(TEXT("TagMatchType"))); CompilerContext.CopyPinLinksToIntermediate(*InPinTagsMatchType, *TagMatchTypePin); UEdGraphPin *OutPin = PinCallFunction->FindPinChecked(K2Schema->PN_ReturnValue); if (OutPinCase && OutPin) { OutPin->PinType = OutPinCase->PinType; // Copy type so it uses the right actor subclass CompilerContext.MovePinLinksToIntermediate(*OutPinCase, *OutPin); } } // Break any links to the expanded node BreakAllNodeLinks(); }
void UK2Node_CastByteToEnum::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { Super::ExpandNode(CompilerContext, SourceGraph); if (bSafe && Enum) { const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema(); // FUNCTION NODE const FName FunctionName = GetFunctionName(); const UFunction* Function = UKismetNodeHelperLibrary::StaticClass()->FindFunctionByName(FunctionName); check(NULL != Function); UK2Node_CallFunction* CallValidation = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); CallValidation->SetFromFunction(Function); CallValidation->AllocateDefaultPins(); check(CallValidation->IsNodePure()); // FUNCTION ENUM PIN UEdGraphPin* FunctionEnumPin = CallValidation->FindPinChecked(TEXT("Enum")); Schema->TrySetDefaultObject(*FunctionEnumPin, Enum); check(FunctionEnumPin->DefaultObject == Enum); // FUNCTION INPUT BYTE PIN UEdGraphPin* OrgInputPin = FindPinChecked(ByteInputPinName); UEdGraphPin* FunctionIndexPin = CallValidation->FindPinChecked(TEXT("EnumeratorIndex")); check(EGPD_Input == FunctionIndexPin->Direction && Schema->PC_Byte == FunctionIndexPin->PinType.PinCategory); CompilerContext.MovePinLinksToIntermediate(*OrgInputPin, *FunctionIndexPin); // UNSAFE CAST NODE UK2Node_CastByteToEnum* UsafeCast = CompilerContext.SpawnIntermediateNode<UK2Node_CastByteToEnum>(this, SourceGraph); UsafeCast->Enum = Enum; UsafeCast->bSafe = false; UsafeCast->AllocateDefaultPins(); // UNSAFE CAST INPUT UEdGraphPin* CastInputPin = UsafeCast->FindPinChecked(ByteInputPinName); UEdGraphPin* FunctionReturnPin = CallValidation->GetReturnValuePin(); check(NULL != FunctionReturnPin); Schema->TryCreateConnection(CastInputPin, FunctionReturnPin); // OPUTPUT PIN UEdGraphPin* OrgReturnPin = FindPinChecked(Schema->PN_ReturnValue); UEdGraphPin* NewReturnPin = UsafeCast->FindPinChecked(Schema->PN_ReturnValue); CompilerContext.MovePinLinksToIntermediate(*OrgReturnPin, *NewReturnPin); BreakAllNodeLinks(); } }
void UK2Node_ForEachElementInEnum::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { if (CompilerContext.bIsFullCompile) { if (!Enum) { ValidateNodeDuringCompilation(CompilerContext.MessageLog); return; } FForExpandNodeHelper ForLoop; if (!ForLoop.BuildLoop(this, CompilerContext, SourceGraph)) { CompilerContext.MessageLog.Error(*NSLOCTEXT("K2Node", "ForEachElementInEnum_ForError", "For Expand error in @@").ToString(), this); } const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema(); CompilerContext.CheckConnectionResponse(Schema->MovePinLinks(*GetExecPin(), *ForLoop.StartLoopExecInPin), this); CompilerContext.CheckConnectionResponse(Schema->MovePinLinks(*FindPinChecked(Schema->PN_Then), *ForLoop.LoopCompleteOutExecPin), this); CompilerContext.CheckConnectionResponse(Schema->MovePinLinks(*FindPinChecked(InsideLoopPinName), *ForLoop.InsideLoopExecOutPin), this); UK2Node_GetNumEnumEntries* GetNumEnumEntries = CompilerContext.SpawnIntermediateNode<UK2Node_GetNumEnumEntries>(this, SourceGraph); GetNumEnumEntries->Enum = Enum; GetNumEnumEntries->AllocateDefaultPins(); bool bResult = Schema->TryCreateConnection(GetNumEnumEntries->FindPinChecked(Schema->PN_ReturnValue), ForLoop.IndexLimitInPin); UK2Node_CallFunction* Conv_Func = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); FName Conv_Func_Name = GET_FUNCTION_NAME_CHECKED(UKismetMathLibrary, Conv_IntToByte); Conv_Func->SetFromFunction(UKismetMathLibrary::StaticClass()->FindFunctionByName(Conv_Func_Name)); Conv_Func->AllocateDefaultPins(); bResult &= Schema->TryCreateConnection(Conv_Func->FindPinChecked(TEXT("InInt")), ForLoop.IndexOutPin); UK2Node_CastByteToEnum* CastByteToEnum = CompilerContext.SpawnIntermediateNode<UK2Node_CastByteToEnum>(this, SourceGraph); CastByteToEnum->Enum = Enum; CastByteToEnum->bSafe = true; CastByteToEnum->AllocateDefaultPins(); bResult &= Schema->TryCreateConnection(Conv_Func->FindPinChecked(Schema->PN_ReturnValue), CastByteToEnum->FindPinChecked(UK2Node_CastByteToEnum::ByteInputPinName)); CompilerContext.CheckConnectionResponse(Schema->MovePinLinks(*FindPinChecked(EnumOuputPinName), *CastByteToEnum->FindPinChecked(Schema->PN_ReturnValue)), this); if (!bResult) { CompilerContext.MessageLog.Error(*NSLOCTEXT("K2Node", "ForEachElementInEnum_ExpandError", "Expand error in @@").ToString(), this); } BreakAllNodeLinks(); } }
void UK2Node_GetNumEnumEntries::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { Super::ExpandNode(CompilerContext, SourceGraph); if(NULL == Enum) { CompilerContext.MessageLog.Error(*FString::Printf(*NSLOCTEXT("K2Node", "GetNumEnumEntries_Error", "@@ must have a valid enum defined").ToString()), this); return; } // Force the enum to load its values if it hasn't already if (Enum->HasAnyFlags(RF_NeedLoad)) { Enum->GetLinker()->Preload(Enum); } const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema(); check(NULL != Schema); //MAKE LITERAL const FName FunctionName = GET_FUNCTION_NAME_CHECKED(UKismetSystemLibrary, MakeLiteralInt); UK2Node_CallFunction* MakeLiteralInt = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); MakeLiteralInt->SetFromFunction(UKismetSystemLibrary::StaticClass()->FindFunctionByName(FunctionName)); MakeLiteralInt->AllocateDefaultPins(); //OPUTPUT PIN UEdGraphPin* OrgReturnPin = FindPinChecked(Schema->PN_ReturnValue); UEdGraphPin* NewReturnPin = MakeLiteralInt->GetReturnValuePin(); check(NULL != NewReturnPin); CompilerContext.MovePinLinksToIntermediate(*OrgReturnPin, *NewReturnPin); //INPUT PIN UEdGraphPin* InputPin = MakeLiteralInt->FindPinChecked(TEXT("Value")); check(EGPD_Input == InputPin->Direction); const FString DefaultValue = FString::FromInt(Enum->NumEnums() - 1); InputPin->DefaultValue = DefaultValue; BreakAllNodeLinks(); }
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_VariableGet::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { Super::ExpandNode(CompilerContext, SourceGraph); // Do not attempt to expand the node when not a pure get nor when there is no property. Normal compilation error detection will detect the missing property. if (!bIsPureGet && GetPropertyForVariable() != nullptr) { const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema(); UEdGraphPin* ValuePin = GetValuePin(); // Impure Get nodes convert into three nodes: // 1. A pure Get node // 2. An IsValid node // 3. A Branch node (only impure part // Create the impure Get node UK2Node_VariableGet* VariableGetNode = CompilerContext.SpawnIntermediateNode<UK2Node_VariableGet>(this, SourceGraph); VariableGetNode->VariableReference = VariableReference; VariableGetNode->AllocateDefaultPins(); CompilerContext.MessageLog.NotifyIntermediateObjectCreation(VariableGetNode, this); // Move pin links from Get node we are expanding, to the new pure one we've created CompilerContext.MovePinLinksToIntermediate(*ValuePin, *VariableGetNode->GetValuePin()); if (!VariableReference.IsLocalScope()) { CompilerContext.MovePinLinksToIntermediate(*FindPin(Schema->PN_Self), *VariableGetNode->FindPin(Schema->PN_Self)); } // Create the IsValid node UK2Node_CallFunction* IsValidFunction = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); // Based on if the type is an "Object" or a "Class" changes which function to use if (ValuePin->PinType.PinCategory == UObject::StaticClass()->GetName()) { IsValidFunction->SetFromFunction(UKismetSystemLibrary::StaticClass()->FindFunctionByName(GET_MEMBER_NAME_CHECKED(UKismetSystemLibrary, IsValid))); } else if (ValuePin->PinType.PinCategory == UClass::StaticClass()->GetName()) { IsValidFunction->SetFromFunction(UKismetSystemLibrary::StaticClass()->FindFunctionByName(GET_MEMBER_NAME_CHECKED(UKismetSystemLibrary, IsValidClass))); } IsValidFunction->AllocateDefaultPins(); CompilerContext.MessageLog.NotifyIntermediateObjectCreation(IsValidFunction, this); // Connect the value pin from the new Get node to the IsValid UEdGraphPin* ObjectPin = IsValidFunction->Pins[1]; check(ObjectPin->Direction == EGPD_Input); ObjectPin->MakeLinkTo(VariableGetNode->GetValuePin()); // Create the Branch node UK2Node_IfThenElse* BranchNode = CompilerContext.SpawnIntermediateNode<UK2Node_IfThenElse>(this, SourceGraph); BranchNode->AllocateDefaultPins(); CompilerContext.MessageLog.NotifyIntermediateObjectCreation(BranchNode, this); // Connect the bool output pin from IsValid node to the Branch node UEdGraphPin* BoolPin = IsValidFunction->Pins[2]; check(BoolPin->Direction == EGPD_Output); BoolPin->MakeLinkTo(BranchNode->GetConditionPin()); // Connect the Branch node to the input of the impure Get node CompilerContext.MovePinLinksToIntermediate(*GetExecPin(), *BranchNode->GetExecPin()); // Move the two Branch pins to the Branch node CompilerContext.MovePinLinksToIntermediate(*FindPin(Schema->PN_Then), *BranchNode->FindPin(Schema->PN_Then)); CompilerContext.MovePinLinksToIntermediate(*FindPin(Schema->PN_Else), *BranchNode->FindPin(Schema->PN_Else)); BreakAllNodeLinks(); } }
void UGameplayTagsK2Node_LiteralGameplayTag::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { Super::ExpandNode(CompilerContext, SourceGraph); const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema(); // Get The input and output pins to our node UEdGraphPin* TagInPin = FindPin(TEXT("TagIn")); UEdGraphPin* TagOutPin = FindPinChecked(Schema->PN_ReturnValue); // Create a Make Struct UK2Node_MakeStruct* MakeStructNode = SourceGraph->CreateBlankNode<UK2Node_MakeStruct>(); MakeStructNode->StructType = FGameplayTagContainer::StaticStruct(); MakeStructNode->AllocateDefaultPins(); // Create a Make Array UK2Node_MakeArray* MakeArrayNode = SourceGraph->CreateBlankNode<UK2Node_MakeArray>(); MakeArrayNode->AllocateDefaultPins(); // Connect the output of our MakeArray to the Input of our MakeStruct so it sets the Array Type UEdGraphPin* InPin = MakeStructNode->FindPin( TEXT("GameplayTags") ); if( InPin ) { InPin->MakeLinkTo( MakeArrayNode->GetOutputPin() ); } // Add the FName Values to the MakeArray input pins UEdGraphPin* ArrayInputPin = NULL; FString TagString = TagInPin->GetDefaultAsString(); if( TagString.StartsWith( TEXT("(") ) && TagString.EndsWith( TEXT(")") ) ) { TagString = TagString.LeftChop(1); TagString = TagString.RightChop(1); TagString.Split("=", NULL, &TagString); TagString = TagString.LeftChop(1); TagString = TagString.RightChop(1); FString ReadTag; FString Remainder; int32 MakeIndex = 0; while( TagString.Split( TEXT(","), &ReadTag, &Remainder ) ) { TagString = Remainder; ArrayInputPin = MakeArrayNode->FindPin( FString::Printf( TEXT("[%d]"), MakeIndex ) ); ArrayInputPin->PinType.PinCategory = TEXT("struct"); ArrayInputPin->PinType.PinSubCategoryObject = FGameplayTag::StaticStruct(); ArrayInputPin->DefaultValue = ReadTag; MakeIndex++; MakeArrayNode->AddInputPin(); } if( Remainder.IsEmpty() ) { Remainder = TagString; } if( !Remainder.IsEmpty() ) { ArrayInputPin = MakeArrayNode->FindPin( FString::Printf( TEXT("[%d]"), MakeIndex ) ); ArrayInputPin->PinType.PinCategory = TEXT("struct"); ArrayInputPin->PinType.PinSubCategoryObject = FGameplayTag::StaticStruct(); ArrayInputPin->DefaultValue = Remainder; MakeArrayNode->PostReconstructNode(); } else { MakeArrayNode->RemoveInputPin(MakeArrayNode->FindPin(TEXT("[0]"))); MakeArrayNode->PostReconstructNode(); } } else { MakeArrayNode->RemoveInputPin(MakeArrayNode->FindPin(TEXT("[0]"))); MakeArrayNode->PostReconstructNode(); } // Move the Output of the MakeArray to the Output of our node UEdGraphPin* OutPin = MakeStructNode->FindPin( MakeStructNode->StructType->GetName() ); if( OutPin && TagOutPin ) { OutPin->PinType = TagOutPin->PinType; // Copy type so it uses the right actor subclass CompilerContext.MovePinLinksToIntermediate(*TagOutPin, *OutPin); } // Break any links to the expanded node BreakAllNodeLinks(); }
void UK2Node_SpawnActor::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { Super::ExpandNode(CompilerContext, SourceGraph); if (CompilerContext.bIsFullCompile) { static FName BeginSpawningBlueprintFuncName = GET_FUNCTION_NAME_CHECKED(UGameplayStatics, BeginSpawningActorFromBlueprint); static FString BlueprintParamName = FString(TEXT("Blueprint")); static FString WorldContextParamName = FString(TEXT("WorldContextObject")); static FName FinishSpawningFuncName = GET_FUNCTION_NAME_CHECKED(UGameplayStatics, FinishSpawningActor); static FString ActorParamName = FString(TEXT("Actor")); static FString TransformParamName = FString(TEXT("SpawnTransform")); static FString NoCollisionFailParamName = FString(TEXT("bNoCollisionFail")); static FString ObjectParamName = FString(TEXT("Object")); static FString ValueParamName = FString(TEXT("Value")); static FString PropertyNameParamName = FString(TEXT("PropertyName")); const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema(); UEdGraphPin* SpawnNodeExec = GetExecPin(); UEdGraphPin* SpawnNodeTransform = GetSpawnTransformPin(); UEdGraphPin* SpawnNodeNoCollisionFail = GetNoCollisionFailPin(); UEdGraphPin* SpawnWorldContextPin = GetWorldContextPin(); UEdGraphPin* SpawnBlueprintPin = GetBlueprintPin(); UEdGraphPin* SpawnNodeThen = GetThenPin(); UEdGraphPin* SpawnNodeResult = GetResultPin(); UBlueprint* SpawnBlueprint = NULL; if(SpawnBlueprintPin != NULL) { SpawnBlueprint = Cast<UBlueprint>(SpawnBlueprintPin->DefaultObject); } if(0 == SpawnBlueprintPin->LinkedTo.Num()) { if(NULL == SpawnBlueprint) { CompilerContext.MessageLog.Error(*LOCTEXT("SpawnActorNodeMissingBlueprint_Error", "Spawn node @@ must have a blueprint specified.").ToString(), this); // we break exec links so this is the only error we get, don't want the SpawnActor node being considered and giving 'unexpected node' type warnings BreakAllNodeLinks(); return; } // check if default blueprint is based on Actor const UClass* GeneratedClass = SpawnBlueprint->GeneratedClass; bool bInvalidBase = GeneratedClass && !GeneratedClass->IsChildOf(AActor::StaticClass()); const UClass* SkeletonGeneratedClass = Cast<UClass>(SpawnBlueprint->SkeletonGeneratedClass); bInvalidBase |= SkeletonGeneratedClass && !SkeletonGeneratedClass->IsChildOf(AActor::StaticClass()); if(bInvalidBase) { CompilerContext.MessageLog.Error(*LOCTEXT("SpawnActorNodeInvalidBlueprint_Error", "Spawn node @@ must have a blueprint based on Actor specified.").ToString(), this); // we break exec links so this is the only error we get, don't want the SpawnActor node being considered and giving 'unexpected node' type warnings BreakAllNodeLinks(); return; } } ////////////////////////////////////////////////////////////////////////// // create 'begin spawn' call node UK2Node_CallFunction* CallBeginSpawnNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); CallBeginSpawnNode->FunctionReference.SetExternalMember(BeginSpawningBlueprintFuncName, UGameplayStatics::StaticClass()); CallBeginSpawnNode->AllocateDefaultPins(); UEdGraphPin* CallBeginExec = CallBeginSpawnNode->GetExecPin(); UEdGraphPin* CallBeginWorldContextPin = CallBeginSpawnNode->FindPinChecked(WorldContextParamName); UEdGraphPin* CallBeginBlueprintPin = CallBeginSpawnNode->FindPinChecked(BlueprintParamName); UEdGraphPin* CallBeginTransform = CallBeginSpawnNode->FindPinChecked(TransformParamName); UEdGraphPin* CallBeginNoCollisionFail = CallBeginSpawnNode->FindPinChecked(NoCollisionFailParamName); UEdGraphPin* CallBeginResult = CallBeginSpawnNode->GetReturnValuePin(); // Move 'exec' connection from spawn node to 'begin spawn' CompilerContext.MovePinLinksToIntermediate(*SpawnNodeExec, *CallBeginExec); if(SpawnBlueprintPin->LinkedTo.Num() > 0) { // Copy the 'blueprint' connection from the spawn node to 'begin spawn' CompilerContext.MovePinLinksToIntermediate(*SpawnBlueprintPin, *CallBeginBlueprintPin); } else { // Copy blueprint literal onto begin spawn call CallBeginBlueprintPin->DefaultObject = SpawnBlueprint; } // Copy the world context connection from the spawn node to 'begin spawn' if necessary if (SpawnWorldContextPin) { CompilerContext.MovePinLinksToIntermediate(*SpawnWorldContextPin, *CallBeginWorldContextPin); } // Copy the 'transform' connection from the spawn node to 'begin spawn' CompilerContext.MovePinLinksToIntermediate(*SpawnNodeTransform, *CallBeginTransform); // Copy the 'bNoCollisionFail' connection from the spawn node to 'begin spawn' CompilerContext.MovePinLinksToIntermediate(*SpawnNodeNoCollisionFail, *CallBeginNoCollisionFail); ////////////////////////////////////////////////////////////////////////// // create 'finish spawn' call node UK2Node_CallFunction* CallFinishSpawnNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); CallFinishSpawnNode->FunctionReference.SetExternalMember(FinishSpawningFuncName, UGameplayStatics::StaticClass()); CallFinishSpawnNode->AllocateDefaultPins(); UEdGraphPin* CallFinishExec = CallFinishSpawnNode->GetExecPin(); UEdGraphPin* CallFinishThen = CallFinishSpawnNode->GetThenPin(); UEdGraphPin* CallFinishActor = CallFinishSpawnNode->FindPinChecked(ActorParamName); UEdGraphPin* CallFinishTransform = CallFinishSpawnNode->FindPinChecked(TransformParamName); UEdGraphPin* CallFinishResult = CallFinishSpawnNode->GetReturnValuePin(); // Move 'then' connection from spawn node to 'finish spawn' CompilerContext.MovePinLinksToIntermediate(*SpawnNodeThen, *CallFinishThen); // Copy transform connection CompilerContext.CopyPinLinksToIntermediate(*CallBeginTransform, *CallFinishTransform); // Connect output actor from 'begin' to 'finish' CallBeginResult->MakeLinkTo(CallFinishActor); // Move result connection from spawn node to 'finish spawn' CallFinishResult->PinType = SpawnNodeResult->PinType; // Copy type so it uses the right actor subclass CompilerContext.MovePinLinksToIntermediate(*SpawnNodeResult, *CallFinishResult); ////////////////////////////////////////////////////////////////////////// // create 'set var' nodes // Get 'result' pin from 'begin spawn', this is the actual actor we want to set properties on UK2Node_CallFunction* LastNode = CallBeginSpawnNode; // Create 'set var by name' nodes and hook them up for(int32 PinIdx=0; PinIdx < Pins.Num(); PinIdx++) { // Only create 'set param by name' node if this pin is linked to something UEdGraphPin* SpawnVarPin = Pins[PinIdx]; if(SpawnVarPin->LinkedTo.Num() > 0) { UFunction* SetByNameFunction = Schema->FindSetVariableByNameFunction(SpawnVarPin->PinType); if(SetByNameFunction) { UK2Node_CallFunction* SetVarNode = NULL; if(SpawnVarPin->PinType.bIsArray) { SetVarNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallArrayFunction>(this, SourceGraph); } else { SetVarNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); } SetVarNode->SetFromFunction(SetByNameFunction); SetVarNode->AllocateDefaultPins(); // Connect this node into the exec chain UEdGraphPin* LastThen = LastNode->GetThenPin(); UEdGraphPin* SetVarExec = SetVarNode->GetExecPin(); LastThen->MakeLinkTo(SetVarExec); // Connect the new actor to the 'object' pin UEdGraphPin* ObjectPin = SetVarNode->FindPinChecked(ObjectParamName); CallBeginResult->MakeLinkTo(ObjectPin); // Fill in literal for 'property name' pin - name of pin is property name UEdGraphPin* PropertyNamePin = SetVarNode->FindPinChecked(PropertyNameParamName); PropertyNamePin->DefaultValue = SpawnVarPin->PinName; // Move connection from the variable pin on the spawn node to the 'value' pin UEdGraphPin* ValuePin = SetVarNode->FindPinChecked(ValueParamName); CompilerContext.MovePinLinksToIntermediate(*SpawnVarPin, *ValuePin); if(SpawnVarPin->PinType.bIsArray) { SetVarNode->PinConnectionListChanged(ValuePin); } // Update 'last node in sequence' var LastNode = SetVarNode; } } } // Make exec connection between 'then' on last node and 'finish' UEdGraphPin* LastThen = LastNode->GetThenPin(); LastThen->MakeLinkTo(CallFinishExec); // Break any links to the expanded node BreakAllNodeLinks(); } }
void UK2Node_LiveEditObject::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { Super::ExpandNode(CompilerContext, SourceGraph); const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema(); UEdGraphPin *SourceExecPin = GetExecPin(); UEdGraphPin *SourceThenPin = GetThenPin(); UEdGraphPin *SourceBlueprintPin = GetBlueprintPin(); UEdGraphPin *SourceBaseClassPin = GetBaseClassPin(); UEdGraphPin *SourceDescriptionPin = GetDescriptionPin(); UEdGraphPin *SourcePermittedBindingsPin = GetPermittedBindingsPin(); UEdGraphPin *SourceOnMidiInputPin = GetOnMidiInputPin(); UEdGraphPin *SourceVariablePin = GetVariablePin(); if(NULL == SourceVariablePin) { CompilerContext.MessageLog.Error(*LOCTEXT("LiveEditObjectNodeMissingBlueprint_Error", "LiveEdit node @@ must have a blueprint specified and a variable selected to tune.").ToString(), this); // we break exec links so this is the only error we get, don't want the SpawnActor node being considered and giving 'unexpected node' type warnings BreakAllNodeLinks(); return; } UClass* SpawnClass = GetClassToSpawn(); if(NULL == SpawnClass) { CompilerContext.MessageLog.Error(*LOCTEXT("LiveEditObjectNodeMissingBaseClass_Error", "LiveEdit node @@ must have a Base Class specified.").ToString(), this); // we break exec links so this is the only error we get, don't want the SpawnActor node being considered and giving 'unexpected node' type warnings BreakAllNodeLinks(); return; } if ( SourcePermittedBindingsPin->LinkedTo.Num() == 0 ) { CompilerContext.MessageLog.Error(*LOCTEXT("LiveEditObjectNodeMissingBinding_Error", "LiveEdit node @@ must specify Permitted Bindings.").ToString(), this); // we break exec links so this is the only error we get, don't want the SpawnActor node being considered and giving 'unexpected node' type warnings BreakAllNodeLinks(); return; } //sanity check the VariablePin value { UProperty *Property = UK2Node_LiveEditObjectStatics::GetPropertyByName( SpawnClass, *SourceVariablePin->DefaultValue ); if ( Property == NULL || !Property->IsA(UNumericProperty::StaticClass()) ) { CompilerContext.MessageLog.Error(*LOCTEXT("LiveEditObjectNodeInvalidVariable_Error", "LiveEdit node @@ must have a valid variable selected.").ToString(), this); // we break exec links so this is the only error we get, don't want the SpawnActor node being considered and giving 'unexpected node' type warnings BreakAllNodeLinks(); return; } } //hooks to pins that are generated after a BaseClass is set UEdGraphPin *DeltaMultPin = GetDeltaMultPin(); UEdGraphPin *ShouldClampPin = GetShouldClampPin(); UEdGraphPin *ClampMinPin = GetClampMinPin(); UEdGraphPin *ClampMaxPin = GetClampMaxPin(); UK2Node_Self *SelfNode = CompilerContext.SpawnIntermediateNode<UK2Node_Self>(this,SourceGraph); SelfNode->AllocateDefaultPins(); UEdGraphPin *SelfNodeThenPin = SelfNode->FindPinChecked(Schema->PN_Self); FString EventNameGuid = GetEventName(); //Create the registration part of the LiveEditor binding process { UK2Node_CallFunction *RegisterForMIDINode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph); RegisterForMIDINode->FunctionReference.SetExternalMember( TEXT("RegisterForLiveEditEvent"), ULiveEditorKismetLibrary::StaticClass() ); RegisterForMIDINode->AllocateDefaultPins(); UEdGraphPin *ExecPin = RegisterForMIDINode->GetExecPin(); CompilerContext.MovePinLinksToIntermediate(*SourceExecPin, *ExecPin); UEdGraphPin *ThenPin = RegisterForMIDINode->GetThenPin(); CompilerContext.MovePinLinksToIntermediate(*SourceThenPin, *ThenPin); UEdGraphPin *TargetPin = RegisterForMIDINode->FindPinChecked( FString(TEXT("Target")) ); TargetPin->MakeLinkTo(SelfNodeThenPin); UEdGraphPin *EventNamePin = RegisterForMIDINode->FindPinChecked( FString(TEXT("EventName")) ); EventNamePin->DefaultValue = EventNameGuid; UEdGraphPin *DescriptionPin = RegisterForMIDINode->FindPinChecked( FString(TEXT("Description")) ); CompilerContext.CopyPinLinksToIntermediate( *SourceDescriptionPin, *DescriptionPin); UEdGraphPin *PermittedBindingsPin = RegisterForMIDINode->FindPinChecked( FString(TEXT("PermittedBindings")) ); CompilerContext.CopyPinLinksToIntermediate( *SourcePermittedBindingsPin, *PermittedBindingsPin); } //Create the event handling part of the LiveEditor binding process { // //the event itself // UFunction *EventMIDISignature = GetEventMIDISignature(); UK2Node_Event* EventNode = CompilerContext.SpawnIntermediateNode<UK2Node_Event>(this, SourceGraph); check(EventNode); EventNode->EventSignatureClass = Cast<UClass>(EventMIDISignature->GetOuter()); EventNode->EventSignatureName = EventMIDISignature->GetFName(); EventNode->CustomFunctionName = *EventNameGuid; EventNode->bInternalEvent = true; EventNode->AllocateDefaultPins(); // Cache these out because we'll connect the sequence to it UEdGraphPin *EventThenPin = EventNode->FindPinChecked( Schema->PN_Then ); UEdGraphPin *EventDeltaPin = EventNode->FindPinChecked( FString(TEXT("Delta")) ); UEdGraphPin *EventMidiValuePin = EventNode->FindPinChecked( FString(TEXT("MidiValue")) ); UEdGraphPin *EventControlTypePin = EventNode->FindPinChecked( FString(TEXT("ControlType")) ); // // Check if Blueprint is NULL // UEdGraphPin *CompareBlueprintToNullBranchThenPin = NULL; { UK2Node_CallFunction *CompareBlueprintToNullNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph); CompareBlueprintToNullNode->FunctionReference.SetExternalMember( TEXT("NotEqual_ObjectObject"), UKismetMathLibrary::StaticClass() ); CompareBlueprintToNullNode->AllocateDefaultPins(); //Set A Pin to the Blueprint Pin UEdGraphPin *CompareBlueprintToNullAPin = CompareBlueprintToNullNode->FindPinChecked( FString(TEXT("A")) ); CompilerContext.CopyPinLinksToIntermediate( *SourceBlueprintPin, *CompareBlueprintToNullAPin); // hook for Compare Blueprint to NULL result UEdGraphPin *CompareBlueprintToNullResultPin = CompareBlueprintToNullNode->GetReturnValuePin(); // Create the BRANCH that will drive the comparison UK2Node_IfThenElse* CompareBlueprintToNullBranchNode = CompilerContext.SpawnIntermediateNode<UK2Node_IfThenElse>(this, SourceGraph); CompareBlueprintToNullBranchNode->AllocateDefaultPins(); //hook up the condition CompareBlueprintToNullResultPin->MakeLinkTo( CompareBlueprintToNullBranchNode->GetConditionPin() ); //hook event to the branck input EventThenPin->MakeLinkTo( CompareBlueprintToNullBranchNode->GetExecPin() ); //cache ot the THEN pin for later linkup CompareBlueprintToNullBranchThenPin = CompareBlueprintToNullBranchNode->GetThenPin(); } // // Get Class Default Object // UK2Node_CallFunction *GetClassDefaultObjectNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph); GetClassDefaultObjectNode->FunctionReference.SetExternalMember( TEXT("GetBlueprintClassDefaultObject"), ULiveEditorKismetLibrary::StaticClass() ); GetClassDefaultObjectNode->AllocateDefaultPins(); UEdGraphPin *GetClassDefaultObjectBlueprintPin = GetClassDefaultObjectNode->FindPinChecked( TEXT("Blueprint") ); CompilerContext.CopyPinLinksToIntermediate( *SourceBlueprintPin, *GetClassDefaultObjectBlueprintPin); //hook for later -> the pointer to the ClassDefaultObject of our BlueprintPin UEdGraphPin *GetClassDefaultObjectResultPin = GetClassDefaultObjectNode->GetReturnValuePin(); // // Compare to BaseClass to make sure that the target Blueprint IsA(BaseClass) // UEdGraphPin *ClassIsChildOfBranchThenPin = NULL; { // //we need to get the class of the Blueprint pin UK2Node_CallFunction *GetClassNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph); GetClassNode->FunctionReference.SetExternalMember( TEXT("GetObjectClass"), UGameplayStatics::StaticClass() ); GetClassNode->AllocateDefaultPins(); //Pin in the GetClassDefaultObjectResultPin to the Object Parameter of the GetObjectClass FUNCTION //we want to make sure that the Class of the DEFAULT_OBJECT IsA( BaseClass ) UEdGraphPin *GetClassObjectPin = GetClassNode->FindPinChecked( FString(TEXT("Object")) ); GetClassDefaultObjectResultPin->MakeLinkTo( GetClassObjectPin ); //hook for the Class result UEdGraphPin *GetClassReturnValuePin = GetClassNode->GetReturnValuePin(); // //the ClassIsChildOf FUNCTION UK2Node_CallFunction *ClassIsChildOfNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph); ClassIsChildOfNode->FunctionReference.SetExternalMember( TEXT("ClassIsChildOf"), UKismetMathLibrary::StaticClass() ); ClassIsChildOfNode->AllocateDefaultPins(); //hook up the test pin UEdGraphPin *ClassIsChildOfTestPin = ClassIsChildOfNode->FindPinChecked( FString(TEXT("TestClass")) ); GetClassReturnValuePin->MakeLinkTo( ClassIsChildOfTestPin ); //copy our BaseClass Pin into the ClassIsChildOf Parameter UEdGraphPin *ClassIsChildOfParentPin = ClassIsChildOfNode->FindPinChecked( FString(TEXT("ParentClass")) ); CompilerContext.CopyPinLinksToIntermediate( *SourceBaseClassPin, *ClassIsChildOfParentPin); //hook for return value UEdGraphPin *ClassIsChildOfResultPin = ClassIsChildOfNode->GetReturnValuePin(); // // Create the BRANCH that will drive the comparison UK2Node_IfThenElse* ClassIsChildOfBranchNode = CompilerContext.SpawnIntermediateNode<UK2Node_IfThenElse>(this, SourceGraph); ClassIsChildOfBranchNode->AllocateDefaultPins(); //hook up the previous branch to this one check( CompareBlueprintToNullBranchThenPin != NULL ); CompareBlueprintToNullBranchThenPin->MakeLinkTo( ClassIsChildOfBranchNode->GetExecPin() ); //hook up our condition ClassIsChildOfResultPin->MakeLinkTo( ClassIsChildOfBranchNode->GetConditionPin() ); //cache ot the THEN pin for later linkup ClassIsChildOfBranchThenPin = ClassIsChildOfBranchNode->GetThenPin(); } // //The set variable function (to set LiveEdited new value) // UK2Node_CallFunction *ModifyVarNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph); ModifyVarNode->FunctionReference.SetExternalMember( TEXT("ModifyPropertyByName"), ULiveEditorKismetLibrary::StaticClass() ); ModifyVarNode->AllocateDefaultPins(); // Make link from the event to the Set variable node UEdGraphPin *ModifyVarExecPin = ModifyVarNode->GetExecPin(); ClassIsChildOfBranchThenPin->MakeLinkTo( ModifyVarExecPin ); //link up the Target Pin UEdGraphPin *ModifyVarNodeTargetPin = ModifyVarNode->FindPinChecked( TEXT("Target") ); GetClassDefaultObjectResultPin->MakeLinkTo( ModifyVarNodeTargetPin ); //link up the PropertyName Pin UEdGraphPin *ModifyVarNodePropertyNamePin = ModifyVarNode->FindPinChecked( TEXT("PropertyName") ); ModifyVarNodePropertyNamePin->DefaultValue = SourceVariablePin->DefaultValue; //link up the MIDI Value Pin UEdGraphPin *ModifyVarNodeMidiValuePin = ModifyVarNode->FindPinChecked( TEXT("MidiValue") ); EventMidiValuePin->MakeLinkTo(ModifyVarNodeMidiValuePin); //link up the ControlType Pin UEdGraphPin *ModifyVarNodeControlTypePin = ModifyVarNode->FindPinChecked( TEXT("ControlType") ); EventControlTypePin->MakeLinkTo(ModifyVarNodeControlTypePin); //hook for the Delta Pin UEdGraphPin *ModifyVarNodeDeltaPin = ModifyVarNode->FindPinChecked( TEXT("Delta") ); //Clamping if ( ShouldClampPin->DefaultValue == FString(TEXT("true")) ) { UEdGraphPin *ModifyVarNodeShouldClampPin = ModifyVarNode->FindPinChecked( TEXT("bShouldClamp") ); CompilerContext.CopyPinLinksToIntermediate( *ShouldClampPin, *ModifyVarNodeShouldClampPin); check( ClampMinPin != NULL ); UEdGraphPin *ModifyVarNodeClampMinPin = ModifyVarNode->FindPinChecked( TEXT("ClampMin") ); CompilerContext.CopyPinLinksToIntermediate( *ClampMinPin, *ModifyVarNodeClampMinPin); check( ClampMaxPin != NULL ); UEdGraphPin *ModifyVarNodeClampMaxPin = ModifyVarNode->FindPinChecked( TEXT("ClampMax") ); CompilerContext.CopyPinLinksToIntermediate( *ClampMaxPin, *ModifyVarNodeClampMaxPin); } //hook for ModifyVar THEN UEdGraphPin *ModifyVarNodeThenPin = ModifyVarNode->GetThenPin(); // // The Multiply Delta * DeltaMult function // UK2Node_CallFunction *MultiplyNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph); MultiplyNode->FunctionReference.SetExternalMember( TEXT("Multiply_FloatFloat"), UKismetMathLibrary::StaticClass() ); MultiplyNode->AllocateDefaultPins(); //cache this out. it will be linked to from the output of the (int)Delta -> (float)Delta Conversion function UEdGraphPin *MultiplyNodeFirstPin = MultiplyNode->FindPinChecked( FString(TEXT("A")) ); // 2nd input to the Add function comes from the Current variable value UEdGraphPin *MultiplyNodeSecondPin = MultiplyNode->FindPinChecked( FString(TEXT("B")) ); CompilerContext.CopyPinLinksToIntermediate( *DeltaMultPin, *MultiplyNodeSecondPin); UEdGraphPin *MultiplyNodeReturnValuePin = MultiplyNode->GetReturnValuePin(); MultiplyNodeReturnValuePin->MakeLinkTo( ModifyVarNodeDeltaPin ); // // The Convert function to go from (int)Delta to ULiveEditorKismetLibrary::ModifyPropertyByName(... float Delta ...) // FName ConvertFunctionName; bool success = Schema->SearchForAutocastFunction( EventDeltaPin, MultiplyNodeFirstPin, ConvertFunctionName ); check( success ); UK2Node_CallFunction *ConvertDeltaNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph); ConvertDeltaNode->FunctionReference.SetExternalMember( ConvertFunctionName, UKismetMathLibrary::StaticClass() ); ConvertDeltaNode->AllocateDefaultPins(); FName PinName; success = UK2Node_LiveEditObjectStatics::SearchForConvertPinName( Schema, EventDeltaPin, PinName ); check( success ); UEdGraphPin *ConvertDeltaInputPin = ConvertDeltaNode->FindPinChecked( PinName.ToString() ); EventDeltaPin->MakeLinkTo( ConvertDeltaInputPin ); UEdGraphPin *ConvertDeltaOutputPin = ConvertDeltaNode->GetReturnValuePin(); ConvertDeltaOutputPin->MakeLinkTo( MultiplyNodeFirstPin ); // // TODO - markDirty // // // send out the object value updates // UK2Node_CallFunction *ReplicationNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this,SourceGraph); ReplicationNode->FunctionReference.SetExternalMember( TEXT("ReplicateChangesToChildren"), ULiveEditorKismetLibrary::StaticClass() ); ReplicationNode->AllocateDefaultPins(); UEdGraphPin *ReplicationNodeVarNamePin = ReplicationNode->FindPinChecked( TEXT("PropertyName") ); ReplicationNodeVarNamePin->DefaultValue = SourceVariablePin->DefaultValue; UEdGraphPin *ReplicationNodeArchetypePin = ReplicationNode->FindPinChecked( FString(TEXT("Archetype")) ); GetClassDefaultObjectResultPin->MakeLinkTo( ReplicationNodeArchetypePin ); UEdGraphPin *ReplicationNodeExecPin = ReplicationNode->GetExecPin(); ModifyVarNodeThenPin->MakeLinkTo( ReplicationNodeExecPin ); UEdGraphPin *ReplicationNodeThenPin = ReplicationNode->FindPinChecked( FString(TEXT("then")) ); // // Finally, activate our OnMidiInput pin // CompilerContext.CopyPinLinksToIntermediate( *SourceOnMidiInputPin, *ReplicationNodeThenPin); } // Break any links to the expanded node BreakAllNodeLinks(); }
void UK2Node_ConvertAsset::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { Super::ExpandNode(CompilerContext, SourceGraph); const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema(); UClass* TargetType = GetTargetClass(); if (TargetType && Schema && (2 == Pins.Num())) { const bool bIsAssetClass = IsAssetClassType(); //Create Convert Function auto ConvertToObjectFunc = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); const FName ConvertFunctionName = bIsAssetClass ? GET_FUNCTION_NAME_CHECKED(UKismetSystemLibrary, Conv_AssetClassToClass) : GET_FUNCTION_NAME_CHECKED(UKismetSystemLibrary, Conv_AssetToObject); ConvertToObjectFunc->FunctionReference.SetExternalMember(ConvertFunctionName, UKismetSystemLibrary::StaticClass()); ConvertToObjectFunc->AllocateDefaultPins(); //Connect input to convert auto InputPin = FindPin(UK2Node_ConvertAssetImpl::InputPinName); const FString ConvertInputName = bIsAssetClass ? FString(TEXT("AssetClass")) : FString(TEXT("Asset")); auto ConvertInput = ConvertToObjectFunc->FindPin(ConvertInputName); bool bIsErrorFree = InputPin && ConvertInput && CompilerContext.MovePinLinksToIntermediate(*InputPin, *ConvertInput).CanSafeConnect(); auto ConvertOutput = ConvertToObjectFunc->GetReturnValuePin(); UEdGraphPin* InnerOutput = nullptr; if (UObject::StaticClass() != TargetType) { //Create Cast Node UK2Node_DynamicCast* CastNode = bIsAssetClass ? CompilerContext.SpawnIntermediateNode<UK2Node_ClassDynamicCast>(this, SourceGraph) : CompilerContext.SpawnIntermediateNode<UK2Node_DynamicCast>(this, SourceGraph); CastNode->SetPurity(true); CastNode->TargetType = TargetType; CastNode->AllocateDefaultPins(); // Connect Object/Class to Cast auto CastInput = CastNode->GetCastSourcePin(); bIsErrorFree &= ConvertOutput && CastInput && Schema->TryCreateConnection(ConvertOutput, CastInput); // Connect output to cast InnerOutput = CastNode->GetCastResultPin(); } else { InnerOutput = ConvertOutput; } auto OutputPin = FindPin(UK2Node_ConvertAssetImpl::OutputPinName); bIsErrorFree &= OutputPin && InnerOutput && CompilerContext.MovePinLinksToIntermediate(*OutputPin, *InnerOutput).CanSafeConnect(); if (!bIsErrorFree) { CompilerContext.MessageLog.Error(*LOCTEXT("InternalConnectionError", "K2Node_ConvertAsset: 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(); } }
void UK2Node_FormatText::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { Super::ExpandNode(CompilerContext, SourceGraph); /** At the end of this, the UK2Node_FormatText will not be a part of the Blueprint, it merely handles connecting the other nodes into the Blueprint. */ const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema(); // Create a "Make Array" node to compile the list of arguments into an array for the Format function being called UK2Node_MakeArray* MakeArrayNode = CompilerContext.SpawnIntermediateNode<UK2Node_MakeArray>(this, SourceGraph); //SourceGraph->CreateBlankNode<UK2Node_MakeArray>(); MakeArrayNode->AllocateDefaultPins(); CompilerContext.MessageLog.NotifyIntermediateObjectCreation(MakeArrayNode, this); UEdGraphPin* ArrayOut = MakeArrayNode->GetOutputPin(); // This is the node that does all the Format work. UK2Node_CallFunction* CallFunction = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); CallFunction->SetFromFunction(UKismetTextLibrary::StaticClass()->FindFunctionByName(GET_MEMBER_NAME_CHECKED(UKismetTextLibrary, Format))); CallFunction->AllocateDefaultPins(); CompilerContext.MessageLog.NotifyIntermediateObjectCreation(CallFunction, this); // Connect the output of the "Make Array" pin to the function's "InArgs" pin ArrayOut->MakeLinkTo(CallFunction->FindPin(TEXT("InArgs"))); // This will set the "Make Array" node's type, only works if one pin is connected. MakeArrayNode->PinConnectionListChanged(ArrayOut); // For each argument, we will need to add in a "Make Struct" node. for(int32 ArgIdx = 0; ArgIdx < PinNames.Num(); ++ArgIdx) { UEdGraphPin* ArgumentPin = FindArgumentPin(PinNames[ArgIdx]); // Spawn a "Make Struct" node to create the struct needed for formatting the text. UK2Node_MakeStruct* PinMakeStruct = CompilerContext.SpawnIntermediateNode<UK2Node_MakeStruct>(this, SourceGraph); PinMakeStruct->StructType = FFormatTextArgument::StaticStruct(); PinMakeStruct->AllocateDefaultPins(); // Set the struct's "ArgumentName" pin literal to be the argument pin's name. PinMakeStruct->GetSchema()->TrySetDefaultText(*PinMakeStruct->FindPin("ArgumentName"), FText::AsCultureInvariant(ArgumentPin->PinName)); // Move the connection of the argument pin to the struct's "TextValue" pin, this will move the literal value if present. CompilerContext.MovePinLinksToIntermediate(*ArgumentPin, *PinMakeStruct->FindPin("TextValue")); // The "Make Array" node already has one pin available, so don't create one for ArgIdx == 0 if(ArgIdx > 0) { MakeArrayNode->AddInputPin(); } // Find the input pin on the "Make Array" node by index. FString PinName = FString::Printf(TEXT("[%d]"), ArgIdx); UEdGraphPin* InputPin = MakeArrayNode->FindPin(PinName); // Find the output for the pin's "Make Struct" node and link it to the corresponding pin on the "Make Array" node. FindOutputStructPinChecked(PinMakeStruct)->MakeLinkTo(InputPin); } // Move connection of FormatText's "Result" pin to the call function's return value pin. CompilerContext.MovePinLinksToIntermediate(*FindPin(TEXT("Result")), *CallFunction->GetReturnValuePin()); // Move connection of FormatText's "Format" pin to the call function's "InPattern" pin CompilerContext.MovePinLinksToIntermediate(*GetFormatPin(), *CallFunction->FindPin(TEXT("InPattern"))); 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(); }
/** * This is essentially a mix of K2Node_BaseAsyncTask::ExpandNode and K2Node_SpawnActorFromClass::ExpandNode. * Several things are going on here: * -Factory call to create proxy object (K2Node_BaseAsyncTask) * -Task return delegates are created and hooked up (K2Node_BaseAsyncTask) * -A BeginSpawn function is called on proxyu object (similiar to K2Node_SpawnActorFromClass) * -BeginSpawn can choose to spawn or not spawn an actor (and return it) * -If spawned: * -SetVars are run on the newly spawned object (set expose on spawn variables - K2Node_SpawnActorFromClass) * -FinishSpawn is called on the proxy object * * * Also, a K2Node_SpawnActorFromClass could not be used directly here, since we want the proxy object to implement its own * BeginSpawn/FinishSpawn function (custom game logic will often be performed in the native implementation). K2Node_SpawnActorFromClass also * requires a SpawnTransform be wired into it, and in most ability task cases, the spawn transform is implied or not necessary. * * */ void UK2Node_LatentAbilityCall::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { bool validatedActorSpawn = ValidateActorSpawning(CompilerContext, false); bool validatedActorArraySpawn = ValidateActorArraySpawning(CompilerContext, false); UEdGraphPin* ClassPin = GetClassPin(); if (ClassPin == nullptr) { // Nothing special about this task, just call super Super::ExpandNode(CompilerContext, SourceGraph); return; } UK2Node::ExpandNode(CompilerContext, SourceGraph); if (!validatedActorSpawn && !validatedActorArraySpawn) { ValidateActorSpawning(CompilerContext, true); ValidateActorArraySpawning(CompilerContext, true); } const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema(); check(SourceGraph && Schema); bool bIsErrorFree = true; // ------------------------------------------------------------------------------------------ // CREATE A CALL TO FACTORY THE PROXY OBJECT // ------------------------------------------------------------------------------------------ UK2Node_CallFunction* const CallCreateProxyObjectNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); CallCreateProxyObjectNode->FunctionReference.SetExternalMember(ProxyFactoryFunctionName, ProxyFactoryClass); CallCreateProxyObjectNode->AllocateDefaultPins(); bIsErrorFree &= CompilerContext.MovePinLinksToIntermediate(*FindPinChecked(Schema->PN_Execute), *CallCreateProxyObjectNode->FindPinChecked(Schema->PN_Execute)).CanSafeConnect(); for (auto CurrentPin : Pins) { if (FBaseAsyncTaskHelper::ValidDataPin(CurrentPin, EGPD_Input, Schema)) { UEdGraphPin* DestPin = CallCreateProxyObjectNode->FindPin(CurrentPin->PinName); // match function inputs, to pass data to function from CallFunction node // NEW: if no DestPin, assume it is a Class Spawn PRoperty - not an error if (DestPin) { bIsErrorFree &= CompilerContext.CopyPinLinksToIntermediate(*CurrentPin, *DestPin).CanSafeConnect(); } } } // ------------------------------------------------------------------------------------------ // GATHER OUTPUT PARAMETERS AND PAIR THEM WITH LOCAL VARIABLES // ------------------------------------------------------------------------------------------ TArray<FBaseAsyncTaskHelper::FOutputPinAndLocalVariable> VariableOutputs; for (auto CurrentPin : Pins) { if (FBaseAsyncTaskHelper::ValidDataPin(CurrentPin, EGPD_Output, Schema)) { const FEdGraphPinType& PinType = CurrentPin->PinType; UK2Node_TemporaryVariable* TempVarOutput = CompilerContext.SpawnInternalVariable( this, PinType.PinCategory, PinType.PinSubCategory, PinType.PinSubCategoryObject.Get(), PinType.bIsArray); bIsErrorFree &= TempVarOutput->GetVariablePin() && CompilerContext.MovePinLinksToIntermediate(*CurrentPin, *TempVarOutput->GetVariablePin()).CanSafeConnect(); VariableOutputs.Add(FBaseAsyncTaskHelper::FOutputPinAndLocalVariable(CurrentPin, TempVarOutput)); } } // ------------------------------------------------------------------------------------------ // FOR EACH DELEGATE DEFINE EVENT, CONNECT IT TO DELEGATE AND IMPLEMENT A CHAIN OF ASSIGMENTS // ------------------------------------------------------------------------------------------ UEdGraphPin* LastThenPin = CallCreateProxyObjectNode->FindPinChecked(Schema->PN_Then); UEdGraphPin* const ProxyObjectPin = CallCreateProxyObjectNode->GetReturnValuePin(); for (TFieldIterator<UMulticastDelegateProperty> PropertyIt(ProxyClass, EFieldIteratorFlags::ExcludeSuper); PropertyIt && bIsErrorFree; ++PropertyIt) { bIsErrorFree &= FBaseAsyncTaskHelper::HandleDelegateImplementation(*PropertyIt, VariableOutputs, ProxyObjectPin, LastThenPin, this, SourceGraph, CompilerContext); } if (CallCreateProxyObjectNode->FindPinChecked(Schema->PN_Then) == LastThenPin) { CompilerContext.MessageLog.Error(*LOCTEXT("MissingDelegateProperties", "BaseAsyncTask: Proxy has no delegates defined. @@").ToString(), this); return; } // ------------------------------------------------------------------------------------------ // NEW: CREATE A CALL TO THE PRESPAWN FUNCTION, IF IT RETURNS TRUE, THEN WE WILL SPAWN THE NEW ACTOR // ------------------------------------------------------------------------------------------ FName ProxyPrespawnFunctionName = validatedActorArraySpawn ? *FK2Node_LatentAbilityCallHelper::BeginSpawnArrayFuncName : *FK2Node_LatentAbilityCallHelper::BeginSpawnFuncName; UFunction* PreSpawnFunction = ProxyFactoryClass->FindFunctionByName(ProxyPrespawnFunctionName); FName ProxyPostpawnFunctionName = validatedActorArraySpawn ? *FK2Node_LatentAbilityCallHelper::FinishSpawnArrayFuncName : *FK2Node_LatentAbilityCallHelper::FinishSpawnFuncName; UFunction* PostSpawnFunction = ProxyFactoryClass->FindFunctionByName(ProxyPostpawnFunctionName); if (PreSpawnFunction == nullptr) { if (validatedActorArraySpawn) { CompilerContext.MessageLog.Error(*LOCTEXT("MissingBeginSpawningActorArrayFunction", "AbilityTask: Proxy is missing BeginSpawningActorArray native function. @@").ToString(), this); } else { CompilerContext.MessageLog.Error(*LOCTEXT("MissingBeginSpawningActorFunction", "AbilityTask: Proxy is missing BeginSpawningActor native function. @@").ToString(), this); } return; } if (PostSpawnFunction == nullptr) { if (validatedActorArraySpawn) { CompilerContext.MessageLog.Error(*LOCTEXT("MissingFinishSpawningActorArrayFunction", "AbilityTask: Proxy is missing FinishSpawningActorArray native function. @@").ToString(), this); } else { CompilerContext.MessageLog.Error(*LOCTEXT("MissingFinishSpawningActorFunction", "AbilityTask: Proxy is missing FinishSpawningActor native function. @@").ToString(), this); } return; } UK2Node_CallFunction* const CallPrespawnProxyObjectNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); CallPrespawnProxyObjectNode->FunctionReference.SetExternalMember(ProxyPrespawnFunctionName, ProxyClass); CallPrespawnProxyObjectNode->AllocateDefaultPins(); // Hook up the self connection UEdGraphPin* PrespawnCallSelfPin = Schema->FindSelfPin(*CallPrespawnProxyObjectNode, EGPD_Input); check(PrespawnCallSelfPin); bIsErrorFree &= Schema->TryCreateConnection(ProxyObjectPin, PrespawnCallSelfPin); // Hook up input parameters to PreSpawn for (auto CurrentPin : Pins) { if (FBaseAsyncTaskHelper::ValidDataPin(CurrentPin, EGPD_Input, Schema)) { UEdGraphPin* DestPin = CallPrespawnProxyObjectNode->FindPin(CurrentPin->PinName); if (DestPin) { bIsErrorFree &= CompilerContext.CopyPinLinksToIntermediate(*CurrentPin, *DestPin).CanSafeConnect(); } } } // Hook the activate node up in the exec chain UEdGraphPin* PrespawnExecPin = CallPrespawnProxyObjectNode->FindPinChecked(Schema->PN_Execute); UEdGraphPin* PrespawnThenPin = CallPrespawnProxyObjectNode->FindPinChecked(Schema->PN_Then); UEdGraphPin* PrespawnReturnPin = CallPrespawnProxyObjectNode->FindPinChecked(Schema->PN_ReturnValue); UEdGraphPin* SpawnedActorReturnPin = CallPrespawnProxyObjectNode->FindPinChecked(FK2Node_LatentAbilityCallHelper::SpawnedActorPinName); bIsErrorFree &= Schema->TryCreateConnection(LastThenPin, PrespawnExecPin); LastThenPin = PrespawnThenPin; // ------------------------------------------- // Branch based on return value of Prespawn // ------------------------------------------- UK2Node_IfThenElse* BranchNode = SourceGraph->CreateBlankNode<UK2Node_IfThenElse>(); BranchNode->AllocateDefaultPins(); CompilerContext.MessageLog.NotifyIntermediateObjectCreation(BranchNode, this); // Link return value of prespawn with the branch condtional bIsErrorFree &= Schema->TryCreateConnection(PrespawnReturnPin, BranchNode->GetConditionPin()); // Link our Prespawn call to the branch node bIsErrorFree &= Schema->TryCreateConnection(LastThenPin, BranchNode->GetExecPin()); UEdGraphPin* BranchElsePin = BranchNode->GetElsePin(); LastThenPin = BranchNode->GetThenPin(); UClass* ClassToSpawn = GetClassToSpawn(); if (validatedActorArraySpawn && ClassToSpawn) { //Branch for main loop control UK2Node_IfThenElse* Branch = CompilerContext.SpawnIntermediateNode<UK2Node_IfThenElse>(this, SourceGraph); Branch->AllocateDefaultPins(); //Create int Iterator UK2Node_TemporaryVariable* IteratorVar = CompilerContext.SpawnIntermediateNode<UK2Node_TemporaryVariable>(this, SourceGraph); IteratorVar->VariableType.PinCategory = Schema->PC_Int; IteratorVar->AllocateDefaultPins(); //Iterator assignment (initialization to zero) UK2Node_AssignmentStatement* IteratorInitialize = CompilerContext.SpawnIntermediateNode<UK2Node_AssignmentStatement>(this, SourceGraph); IteratorInitialize->AllocateDefaultPins(); IteratorInitialize->GetValuePin()->DefaultValue = TEXT("0"); //Iterator assignment (incrementing) UK2Node_AssignmentStatement* IteratorAssign = CompilerContext.SpawnIntermediateNode<UK2Node_AssignmentStatement>(this, SourceGraph); IteratorAssign->AllocateDefaultPins(); //Increment iterator command UK2Node_CallFunction* Increment = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); Increment->SetFromFunction(UKismetMathLibrary::StaticClass()->FindFunctionByName(TEXT("Add_IntInt"))); Increment->AllocateDefaultPins(); Increment->FindPinChecked(TEXT("B"))->DefaultValue = TEXT("1"); //Array length UK2Node_CallArrayFunction* ArrayLength = CompilerContext.SpawnIntermediateNode<UK2Node_CallArrayFunction>(this, SourceGraph); ArrayLength->SetFromFunction(UKismetArrayLibrary::StaticClass()->FindFunctionByName(TEXT("Array_Length"))); ArrayLength->AllocateDefaultPins(); //Array element retrieval UK2Node_CallArrayFunction* GetElement = CompilerContext.SpawnIntermediateNode<UK2Node_CallArrayFunction>(this, SourceGraph); GetElement->SetFromFunction(UKismetArrayLibrary::StaticClass()->FindFunctionByName(TEXT("Array_Get"))); GetElement->AllocateDefaultPins(); //Check node for iterator versus array length UK2Node_CallFunction* Condition = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); Condition->SetFromFunction(UKismetMathLibrary::StaticClass()->FindFunctionByName(TEXT("Less_IntInt"))); Condition->AllocateDefaultPins(); //Connections to set up the loop UEdGraphSchema_K2 const* const K2Schema = Cast<const UEdGraphSchema_K2>(Schema); bIsErrorFree &= Schema->TryCreateConnection(LastThenPin, IteratorInitialize->GetExecPin()); bIsErrorFree &= Schema->TryCreateConnection(IteratorVar->GetVariablePin(), IteratorInitialize->GetVariablePin()); bIsErrorFree &= Schema->TryCreateConnection(IteratorInitialize->GetThenPin(), Branch->GetExecPin()); bIsErrorFree &= Schema->TryCreateConnection(SpawnedActorReturnPin, ArrayLength->GetTargetArrayPin()); bIsErrorFree &= Schema->TryCreateConnection(Condition->GetReturnValuePin(), Branch->GetConditionPin()); bIsErrorFree &= Schema->TryCreateConnection(IteratorVar->GetVariablePin(), Condition->FindPinChecked(TEXT("A"))); bIsErrorFree &= Schema->TryCreateConnection(ArrayLength->FindPin(K2Schema->PN_ReturnValue), Condition->FindPinChecked(TEXT("B"))); //Connections to establish loop iteration bIsErrorFree &= Schema->TryCreateConnection(IteratorVar->GetVariablePin(), Increment->FindPinChecked(TEXT("A"))); bIsErrorFree &= Schema->TryCreateConnection(IteratorVar->GetVariablePin(), IteratorAssign->GetVariablePin()); bIsErrorFree &= Schema->TryCreateConnection(Increment->GetReturnValuePin(), IteratorAssign->GetValuePin()); bIsErrorFree &= Schema->TryCreateConnection(IteratorAssign->GetThenPin(), Branch->GetExecPin()); //This is the inner loop LastThenPin = Branch->GetThenPin(); //Connect the loop branch to the spawn-assignment code block bIsErrorFree &= Schema->TryCreateConnection(SpawnedActorReturnPin, GetElement->GetTargetArrayPin()); bIsErrorFree &= Schema->TryCreateConnection(IteratorVar->GetVariablePin(), GetElement->FindPinChecked(K2Schema->PN_Index)); bIsErrorFree &= ConnectSpawnProperties(ClassToSpawn, Schema, CompilerContext, SourceGraph, LastThenPin, GetElement->FindPinChecked(K2Schema->PN_Item)); //Last argument is the array element bIsErrorFree &= Schema->TryCreateConnection(LastThenPin, IteratorAssign->GetExecPin()); //Connect the spawn-assignment code block to the iterator increment //Finish by providing the proper path out LastThenPin = Branch->GetElsePin(); } // ------------------------------------------- // Set spawn variables // Borrowed heavily from FKismetCompilerUtilities::GenerateAssignmentNodes // ------------------------------------------- if (validatedActorSpawn && ClassToSpawn) { bIsErrorFree &= ConnectSpawnProperties(ClassToSpawn, Schema, CompilerContext, SourceGraph, LastThenPin, SpawnedActorReturnPin); } // ------------------------------------------- // Call FinishSpawning // ------------------------------------------- UK2Node_CallFunction* const CallPostSpawnnProxyObjectNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); CallPostSpawnnProxyObjectNode->FunctionReference.SetExternalMember(ProxyPostpawnFunctionName, ProxyClass); CallPostSpawnnProxyObjectNode->AllocateDefaultPins(); // Hook up the self connection UEdGraphPin* PostspawnCallSelfPin = Schema->FindSelfPin(*CallPostSpawnnProxyObjectNode, EGPD_Input); check(PostspawnCallSelfPin); bIsErrorFree &= Schema->TryCreateConnection(ProxyObjectPin, PostspawnCallSelfPin); // Link our Postspawn call in bIsErrorFree &= Schema->TryCreateConnection(LastThenPin, CallPostSpawnnProxyObjectNode->FindPinChecked(Schema->PN_Execute)); // Hook up any other input parameters to PostSpawn for (auto CurrentPin : Pins) { if (FBaseAsyncTaskHelper::ValidDataPin(CurrentPin, EGPD_Input, Schema)) { UEdGraphPin* DestPin = CallPostSpawnnProxyObjectNode->FindPin(CurrentPin->PinName); if (DestPin) { bIsErrorFree &= CompilerContext.CopyPinLinksToIntermediate(*CurrentPin, *DestPin).CanSafeConnect(); } } } UEdGraphPin* InSpawnedActorPin = CallPostSpawnnProxyObjectNode->FindPin(TEXT("SpawnedActor")); if (InSpawnedActorPin == nullptr) { CompilerContext.MessageLog.Error(*LOCTEXT("MissingSpawnedActorInputPin", "AbilityTask: Proxy is missing SpawnedActor input pin in FinishSpawningActor. @@").ToString(), this); return; } bIsErrorFree &= Schema->TryCreateConnection(SpawnedActorReturnPin, InSpawnedActorPin); LastThenPin = CallPostSpawnnProxyObjectNode->FindPinChecked(Schema->PN_Then); // Move the connections from the original node then pin to the last internal then pin bIsErrorFree &= CompilerContext.MovePinLinksToIntermediate(*FindPinChecked(Schema->PN_Then), *LastThenPin).CanSafeConnect(); bIsErrorFree &= CompilerContext.CopyPinLinksToIntermediate(*LastThenPin, *BranchElsePin).CanSafeConnect(); if (!bIsErrorFree) { CompilerContext.MessageLog.Error(*LOCTEXT("InternalConnectionError", "BaseAsyncTask: Internal connection error. @@").ToString(), this); } // Make sure we caught everything BreakAllNodeLinks(); }
void UK2Node_GetEnumeratorName::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { Super::ExpandNode(CompilerContext, SourceGraph); UEnum* Enum = GetEnum(); if(NULL == Enum) { CompilerContext.MessageLog.Error(*FString::Printf(*NSLOCTEXT("K2Node", "GetEnumeratorNam_Error_MustHaveValidName", "@@ must have a valid enum defined").ToString()), this); return; } const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema(); const UFunction* Function = UKismetNodeHelperLibrary::StaticClass()->FindFunctionByName( GetFunctionName() ); check(NULL != Function); UK2Node_CallFunction* CallGetName = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); CallGetName->SetFromFunction(Function); CallGetName->AllocateDefaultPins(); check(CallGetName->IsNodePure()); //OPUTPUT PIN UEdGraphPin* OrgReturnPin = FindPinChecked(Schema->PN_ReturnValue); UEdGraphPin* NewReturnPin = CallGetName->GetReturnValuePin(); check(NULL != NewReturnPin); CompilerContext.MovePinLinksToIntermediate(*OrgReturnPin, *NewReturnPin); //ENUM PIN UEdGraphPin* EnumPin = CallGetName->FindPinChecked(TEXT("Enum")); Schema->TrySetDefaultObject(*EnumPin, Enum); check(EnumPin->DefaultObject == Enum); //VALUE PIN UEdGraphPin* OrgInputPin = FindPinChecked(EnumeratorPinName); UEdGraphPin* IndexPin = CallGetName->FindPinChecked(TEXT("EnumeratorValue")); check(EGPD_Input == IndexPin->Direction && Schema->PC_Byte == IndexPin->PinType.PinCategory); CompilerContext.MovePinLinksToIntermediate(*OrgInputPin, *IndexPin); if (!IndexPin->LinkedTo.Num()) { //MAKE LITERAL BYTE FROM LITERAL ENUM const FString EnumLiteral = IndexPin->GetDefaultAsString(); const int32 NumericValue = Enum->GetValueByName(*EnumLiteral); if (NumericValue == INDEX_NONE) { CompilerContext.MessageLog.Error(*FString::Printf(*NSLOCTEXT("K2Node", "GetEnumeratorNam_Error_InvalidName", "@@ has invalid enum value '%s'").ToString(), *EnumLiteral), this); return; } const FString DefaultByteValue = FString::FromInt(NumericValue); // LITERAL BYTE FUNCTION const FName FunctionName = GET_FUNCTION_NAME_CHECKED(UKismetSystemLibrary, MakeLiteralByte); UK2Node_CallFunction* MakeLiteralByte = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph); MakeLiteralByte->SetFromFunction(UKismetSystemLibrary::StaticClass()->FindFunctionByName(FunctionName)); MakeLiteralByte->AllocateDefaultPins(); UEdGraphPin* MakeLiteralByteReturnPin = MakeLiteralByte->FindPinChecked(Schema->PN_ReturnValue); Schema->TryCreateConnection(MakeLiteralByteReturnPin, IndexPin); UEdGraphPin* MakeLiteralByteInputPin = MakeLiteralByte->FindPinChecked(TEXT("Value")); MakeLiteralByteInputPin->DefaultValue = DefaultByteValue; } BreakAllNodeLinks(); }