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_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 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_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(); }