void UK2Node_FunctionEntry::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { Super::ExpandNode(CompilerContext, SourceGraph); const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema(); UEdGraphPin* OldStartExecPin = nullptr; if(Pins[0]->LinkedTo.Num()) { OldStartExecPin = Pins[0]->LinkedTo[0]; } UEdGraphPin* LastActiveOutputPin = Pins[0]; // Only look for FunctionEntry nodes who were duplicated and have a source object if ( UK2Node_FunctionEntry* OriginalNode = Cast<UK2Node_FunctionEntry>(CompilerContext.MessageLog.FindSourceObject(this)) ) { check(OriginalNode->GetOuter()); // Find the associated UFunction UFunction* Function = FindField<UFunction>(CompilerContext.Blueprint->SkeletonGeneratedClass, *OriginalNode->GetOuter()->GetName()); for (TFieldIterator<UProperty> It(Function); It; ++It) { if (const UProperty* Property = *It) { for (auto& LocalVar : LocalVariables) { if (LocalVar.VarName == Property->GetFName() && !LocalVar.DefaultValue.IsEmpty()) { // Add a variable set node for the local variable and hook it up immediately following the entry node or the last added local variable UK2Node_VariableSet* VariableSetNode = CompilerContext.SpawnIntermediateNode<UK2Node_VariableSet>(this, SourceGraph); VariableSetNode->SetFromProperty(Property, false); Schema->ConfigureVarNode(VariableSetNode, LocalVar.VarName, Function, CompilerContext.Blueprint); VariableSetNode->AllocateDefaultPins(); CompilerContext.MessageLog.NotifyIntermediateObjectCreation(VariableSetNode, this); if(UEdGraphPin* SetPin = VariableSetNode->FindPin(Property->GetName())) { if(LocalVar.VarType.bIsArray) { TSharedPtr<FStructOnScope> StructData = MakeShareable(new FStructOnScope(Function)); FBlueprintEditorUtils::PropertyValueFromString(Property, LocalVar.DefaultValue, StructData->GetStructMemory()); // Create a Make Array node to setup the array's defaults UK2Node_MakeArray* MakeArray = CompilerContext.SpawnIntermediateNode<UK2Node_MakeArray>(this, SourceGraph); MakeArray->AllocateDefaultPins(); MakeArray->GetOutputPin()->MakeLinkTo(SetPin); MakeArray->PostReconstructNode(); const UArrayProperty* ArrayProperty = Cast<UArrayProperty>(Property); check(ArrayProperty); FScriptArrayHelper_InContainer ArrayHelper(ArrayProperty, StructData->GetStructMemory()); FScriptArrayHelper_InContainer DefaultArrayHelper(ArrayProperty, StructData->GetStructMemory()); uint8* StructDefaults = NULL; UStructProperty* StructProperty = dynamic_cast<UStructProperty*>(ArrayProperty->Inner); if ( StructProperty != NULL ) { checkSlow(StructProperty->Struct); StructDefaults = (uint8*)FMemory::Malloc(StructProperty->Struct->GetStructureSize()); StructProperty->InitializeValue(StructDefaults); } // Go through each element in the array to set the default value for( int32 ArrayIndex = 0 ; ArrayIndex < ArrayHelper.Num() ; ArrayIndex++ ) { uint8* PropData = ArrayHelper.GetRawPtr(ArrayIndex); // Always use struct defaults if the inner is a struct, for symmetry with the import of array inner struct defaults uint8* PropDefault = ( StructProperty != NULL ) ? StructDefaults : ( ( StructData->GetStructMemory() && DefaultArrayHelper.Num() > ArrayIndex ) ? DefaultArrayHelper.GetRawPtr(ArrayIndex) : NULL ); // Retrieve the element's default value FString DefaultValue; FBlueprintEditorUtils::PropertyValueToString(ArrayProperty->Inner, PropData, DefaultValue); if(ArrayIndex > 0) { MakeArray->AddInputPin(); } // Add one to the index for the pin to set the default on to skip the output pin Schema->TrySetDefaultValue(*MakeArray->Pins[ArrayIndex + 1], DefaultValue); } } else { // Set the default value Schema->TrySetDefaultValue(*SetPin, LocalVar.DefaultValue); } } LastActiveOutputPin->BreakAllPinLinks(); LastActiveOutputPin->MakeLinkTo(VariableSetNode->Pins[0]); LastActiveOutputPin = VariableSetNode->Pins[1]; } } } } // Finally, hook up the last node to the old node the function entry node was connected to if(OldStartExecPin) { LastActiveOutputPin->MakeLinkTo(OldStartExecPin); } } }
virtual void Compile(FKismetFunctionContext& Context, UEdGraphNode* Node) override { UK2Node_MakeArray* ArrayNode = CastChecked<UK2Node_MakeArray>(Node); UEdGraphPin* OutputPin = ArrayNode->GetOutputPin(); FBPTerminal** ArrayTerm = Context.NetMap.Find(OutputPin); check(ArrayTerm); FBlueprintCompiledStatement& CreateArrayStatement = Context.AppendStatementForNode(Node); CreateArrayStatement.Type = KCST_CreateArray; CreateArrayStatement.LHS = *ArrayTerm; for(auto PinIt = Node->Pins.CreateIterator(); PinIt; ++PinIt) { UEdGraphPin* Pin = *PinIt; if(Pin && Pin->Direction == EGPD_Input) { FBPTerminal** InputTerm = Context.NetMap.Find(FEdGraphUtilities::GetNetFromPin(Pin)); if( InputTerm ) { CreateArrayStatement.RHS.Add(*InputTerm); } } } }
virtual void RegisterNets(FKismetFunctionContext& Context, UEdGraphNode* Node) override { UK2Node_MakeArray* ArrayNode = CastChecked<UK2Node_MakeArray>(Node); UEdGraphPin* OutputPin = ArrayNode->GetOutputPin(); FNodeHandlingFunctor::RegisterNets(Context, Node); // Create a local term to drop the array into FBPTerminal* Term = Context.CreateLocalTerminalFromPinAutoChooseScope(OutputPin, Context.NetNameMap->MakeValidName(OutputPin)); Term->bPassedByReference = false; Term->Source = Node; Context.NetMap.Add(OutputPin, Term); }
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 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(); }