541 lines
20 KiB
C++
541 lines
20 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "K2Node_SpawnActor.h"
|
|
|
|
#include "Containers/EnumAsByte.h"
|
|
#include "Containers/UnrealString.h"
|
|
#include "EdGraph/EdGraph.h"
|
|
#include "EdGraph/EdGraphPin.h"
|
|
#include "EdGraphSchema_K2.h"
|
|
#include "Engine/Blueprint.h"
|
|
#include "Engine/MemberReference.h"
|
|
#include "GameFramework/Actor.h"
|
|
#include "HAL/PlatformMath.h"
|
|
#include "Internationalization/Internationalization.h"
|
|
#include "K2Node_CallArrayFunction.h"
|
|
#include "K2Node_CallFunction.h"
|
|
#include "Kismet/GameplayStatics.h"
|
|
#include "Kismet2/BlueprintEditorUtils.h"
|
|
#include "Kismet2/CompilerResultsLog.h"
|
|
#include "KismetCompiler.h"
|
|
#include "KismetCompilerMisc.h"
|
|
#include "Math/Transform.h"
|
|
#include "Misc/AssertionMacros.h"
|
|
#include "Styling/AppStyle.h"
|
|
#include "Templates/Casts.h"
|
|
#include "Templates/SubclassOf.h"
|
|
#include "Templates/UnrealTemplate.h"
|
|
#include "UObject/Class.h"
|
|
#include "UObject/NameTypes.h"
|
|
#include "UObject/Object.h"
|
|
#include "UObject/ObjectPtr.h"
|
|
#include "UObject/UnrealNames.h"
|
|
#include "UObject/UnrealType.h"
|
|
#include "UObject/WeakObjectPtr.h"
|
|
#include "UObject/WeakObjectPtrTemplates.h"
|
|
|
|
struct FK2Node_SpawnActorHelper
|
|
{
|
|
static const FName WorldContextPinName;
|
|
static const FName BlueprintPinName;
|
|
static const FName SpawnTransformPinName;
|
|
static const FName NoCollisionFailPinName;
|
|
};
|
|
|
|
const FName FK2Node_SpawnActorHelper::WorldContextPinName(TEXT("WorldContextObject"));
|
|
const FName FK2Node_SpawnActorHelper::BlueprintPinName(TEXT("Blueprint"));
|
|
const FName FK2Node_SpawnActorHelper::SpawnTransformPinName(TEXT("SpawnTransform"));
|
|
const FName FK2Node_SpawnActorHelper::NoCollisionFailPinName(TEXT("SpawnEvenIfColliding"));
|
|
|
|
#define LOCTEXT_NAMESPACE "K2Node_SpawnActor"
|
|
|
|
UK2Node_SpawnActor::UK2Node_SpawnActor(const FObjectInitializer& ObjectInitializer)
|
|
: Super(ObjectInitializer)
|
|
{
|
|
NodeTooltip = LOCTEXT("NodeTooltip", "Attempts to spawn a new Actor with the specified transform");
|
|
}
|
|
|
|
void UK2Node_SpawnActor::AllocateDefaultPins()
|
|
{
|
|
UEdGraphSchema_K2 const* K2Schema = GetDefault<UEdGraphSchema_K2>();
|
|
|
|
// Add execution pins
|
|
CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Execute);
|
|
CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Then);
|
|
|
|
// If required add the world context pin
|
|
if (GetBlueprint()->ParentClass->HasMetaDataHierarchical(FBlueprintMetadata::MD_ShowWorldContextPin))
|
|
{
|
|
CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Object, UObject::StaticClass(), FK2Node_SpawnActorHelper::WorldContextPinName);
|
|
}
|
|
|
|
// Add blueprint pin
|
|
UEdGraphPin* BlueprintPin = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Object, UBlueprint::StaticClass(), FK2Node_SpawnActorHelper::BlueprintPinName);
|
|
K2Schema->ConstructBasicPinTooltip(*BlueprintPin, LOCTEXT("BlueprintPinDescription", "The blueprint Actor you want to spawn"), BlueprintPin->PinToolTip);
|
|
|
|
// Transform pin
|
|
UScriptStruct* TransformStruct = TBaseStructure<FTransform>::Get();
|
|
UEdGraphPin* TransformPin = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Struct, TransformStruct, FK2Node_SpawnActorHelper::SpawnTransformPinName);
|
|
K2Schema->ConstructBasicPinTooltip(*TransformPin, LOCTEXT("TransformPinDescription", "The transform to spawn the Actor with"), TransformPin->PinToolTip);
|
|
|
|
// bNoCollisionFail pin
|
|
UEdGraphPin* NoCollisionFailPin = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Boolean, FK2Node_SpawnActorHelper::NoCollisionFailPinName);
|
|
K2Schema->ConstructBasicPinTooltip(*NoCollisionFailPin, LOCTEXT("NoCollisionFailPinDescription", "Determines if the Actor should be spawned when the location is blocked by a collision"), NoCollisionFailPin->PinToolTip);
|
|
|
|
// Result pin
|
|
UEdGraphPin* ResultPin = CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Object, AActor::StaticClass(), UEdGraphSchema_K2::PN_ReturnValue);
|
|
K2Schema->ConstructBasicPinTooltip(*ResultPin, LOCTEXT("ResultPinDescription", "The spawned Actor"), ResultPin->PinToolTip);
|
|
|
|
Super::AllocateDefaultPins();
|
|
}
|
|
|
|
void UK2Node_SpawnActor::CreatePinsForClass(UClass* InClass)
|
|
{
|
|
check(InClass != NULL);
|
|
|
|
const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
|
|
|
|
for (TFieldIterator<FProperty> PropertyIt(InClass, EFieldIteratorFlags::IncludeSuper); PropertyIt; ++PropertyIt)
|
|
{
|
|
FProperty* Property = *PropertyIt;
|
|
UClass* PropertyClass = CastChecked<UClass>(Property->GetOwner<UObject>());
|
|
const bool bIsDelegate = Property->IsA(FMulticastDelegateProperty::StaticClass());
|
|
const bool bIsExposedToSpawn = UEdGraphSchema_K2::IsPropertyExposedOnSpawn(Property);
|
|
const bool bIsSettableExternally = !Property->HasAnyPropertyFlags(CPF_DisableEditOnInstance);
|
|
|
|
if( bIsExposedToSpawn &&
|
|
!Property->HasAnyPropertyFlags(CPF_Parm) &&
|
|
bIsSettableExternally &&
|
|
Property->HasAllPropertyFlags(CPF_BlueprintVisible) &&
|
|
!bIsDelegate )
|
|
{
|
|
UEdGraphPin* Pin = CreatePin(EGPD_Input, NAME_None, Property->GetFName());
|
|
const bool bPinGood = (Pin != nullptr) && K2Schema->ConvertPropertyToPinType(Property, /*out*/ Pin->PinType);
|
|
|
|
// Copy tooltip from the property.
|
|
if (Pin != nullptr)
|
|
{
|
|
K2Schema->ConstructBasicPinTooltip(*Pin, Property->GetToolTipText(), Pin->PinToolTip);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Change class of output pin
|
|
UEdGraphPin* ResultPin = GetResultPin();
|
|
ResultPin->PinType.PinSubCategoryObject = InClass;
|
|
}
|
|
|
|
UClass* UK2Node_SpawnActor::GetClassToSpawn(const TArray<UEdGraphPin*>* InPinsToSearch /*=NULL*/) const
|
|
{
|
|
UClass* UseSpawnClass = NULL;
|
|
const TArray<UEdGraphPin*>* PinsToSearch = InPinsToSearch ? InPinsToSearch : &Pins;
|
|
|
|
UEdGraphPin* BlueprintPin = GetBlueprintPin(PinsToSearch);
|
|
if(BlueprintPin && BlueprintPin->DefaultObject != NULL && BlueprintPin->LinkedTo.Num() == 0)
|
|
{
|
|
UBlueprint* BP = CastChecked<UBlueprint>(BlueprintPin->DefaultObject);
|
|
UseSpawnClass = BP->GeneratedClass;
|
|
}
|
|
|
|
return UseSpawnClass;
|
|
}
|
|
|
|
void UK2Node_SpawnActor::ReallocatePinsDuringReconstruction(TArray<UEdGraphPin*>& OldPins)
|
|
{
|
|
AllocateDefaultPins();
|
|
UClass* UseSpawnClass = GetClassToSpawn(&OldPins);
|
|
if( UseSpawnClass != NULL )
|
|
{
|
|
CreatePinsForClass(UseSpawnClass);
|
|
}
|
|
|
|
RestoreSplitPins(OldPins);
|
|
}
|
|
|
|
bool UK2Node_SpawnActor::IsSpawnVarPin(UEdGraphPin* Pin) const
|
|
{
|
|
if (Pin->ParentPin)
|
|
{
|
|
return IsSpawnVarPin(Pin->ParentPin);
|
|
}
|
|
|
|
return( Pin->PinName != UEdGraphSchema_K2::PN_Execute &&
|
|
Pin->PinName != UEdGraphSchema_K2::PN_Then &&
|
|
Pin->PinName != UEdGraphSchema_K2::PN_ReturnValue &&
|
|
Pin->PinName != FK2Node_SpawnActorHelper::BlueprintPinName &&
|
|
Pin->PinName != FK2Node_SpawnActorHelper::WorldContextPinName &&
|
|
Pin->PinName != FK2Node_SpawnActorHelper::NoCollisionFailPinName &&
|
|
Pin->PinName != FK2Node_SpawnActorHelper::SpawnTransformPinName );
|
|
}
|
|
|
|
|
|
void UK2Node_SpawnActor::PinDefaultValueChanged(UEdGraphPin* ChangedPin)
|
|
{
|
|
if (ChangedPin->PinName == FK2Node_SpawnActorHelper::BlueprintPinName)
|
|
{
|
|
const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
|
|
|
|
// Because the archetype has changed, we break the output link as the output pin type will change
|
|
UEdGraphPin* ResultPin = GetResultPin();
|
|
ResultPin->BreakAllPinLinks();
|
|
|
|
// Remove all pins related to archetype variables
|
|
TArray<UEdGraphPin*> OldPins = Pins;
|
|
for (int32 i = 0; i < OldPins.Num(); i++)
|
|
{
|
|
UEdGraphPin* OldPin = OldPins[i];
|
|
if (IsSpawnVarPin(OldPin))
|
|
{
|
|
OldPin->MarkAsGarbage();
|
|
Pins.Remove(OldPin);
|
|
}
|
|
}
|
|
|
|
CachedNodeTitle.MarkDirty();
|
|
|
|
UClass* UseSpawnClass = GetClassToSpawn();
|
|
if(UseSpawnClass != NULL)
|
|
{
|
|
CreatePinsForClass(UseSpawnClass);
|
|
}
|
|
|
|
// Refresh the UI for the graph so the pin changes show up
|
|
UEdGraph* Graph = GetGraph();
|
|
Graph->NotifyNodeChanged(this);
|
|
|
|
// Mark dirty
|
|
FBlueprintEditorUtils::MarkBlueprintAsModified(GetBlueprint());
|
|
}
|
|
}
|
|
|
|
FText UK2Node_SpawnActor::GetTooltipText() const
|
|
{
|
|
return NodeTooltip;
|
|
}
|
|
|
|
UEdGraphPin* UK2Node_SpawnActor::GetBlueprintPin(const TArray<UEdGraphPin*>* InPinsToSearch /*= NULL*/) const
|
|
{
|
|
const TArray<UEdGraphPin*>* PinsToSearch = InPinsToSearch ? InPinsToSearch : &Pins;
|
|
|
|
UEdGraphPin* Pin = nullptr;
|
|
for (UEdGraphPin* TestPin : *PinsToSearch)
|
|
{
|
|
if( TestPin && TestPin->PinName == FK2Node_SpawnActorHelper::BlueprintPinName )
|
|
{
|
|
Pin = TestPin;
|
|
break;
|
|
}
|
|
}
|
|
check(Pin == nullptr || Pin->Direction == EGPD_Input);
|
|
return Pin;
|
|
}
|
|
|
|
UEdGraphPin* UK2Node_SpawnActor::GetSpawnTransformPin()const
|
|
{
|
|
UEdGraphPin* Pin = FindPinChecked(FK2Node_SpawnActorHelper::SpawnTransformPinName);
|
|
check(Pin->Direction == EGPD_Input);
|
|
return Pin;
|
|
}
|
|
|
|
UEdGraphPin* UK2Node_SpawnActor::GetNoCollisionFailPin()const
|
|
{
|
|
UEdGraphPin* Pin = FindPinChecked(FK2Node_SpawnActorHelper::NoCollisionFailPinName);
|
|
check(Pin->Direction == EGPD_Input);
|
|
return Pin;
|
|
}
|
|
|
|
UEdGraphPin* UK2Node_SpawnActor::GetWorldContextPin() const
|
|
{
|
|
UEdGraphPin* Pin = FindPin(FK2Node_SpawnActorHelper::WorldContextPinName);
|
|
check(Pin == NULL || Pin->Direction == EGPD_Input);
|
|
return Pin;
|
|
}
|
|
|
|
UEdGraphPin* UK2Node_SpawnActor::GetResultPin() const
|
|
{
|
|
UEdGraphPin* Pin = FindPinChecked(UEdGraphSchema_K2::PN_ReturnValue);
|
|
check(Pin->Direction == EGPD_Output);
|
|
return Pin;
|
|
}
|
|
|
|
FLinearColor UK2Node_SpawnActor::GetNodeTitleColor() const
|
|
{
|
|
return Super::GetNodeTitleColor();
|
|
}
|
|
|
|
|
|
FText UK2Node_SpawnActor::GetNodeTitle(ENodeTitleType::Type TitleType) const
|
|
{
|
|
UEdGraphPin* BlueprintPin = GetBlueprintPin();
|
|
if (BlueprintPin == NULL)
|
|
{
|
|
return NSLOCTEXT("K2Node", "SpawnActorNone_Title", "SpawnActor NONE");
|
|
}
|
|
else if (BlueprintPin->LinkedTo.Num() > 0)
|
|
{
|
|
// Blueprint will be determined dynamically, so we don't have the name in this case
|
|
return NSLOCTEXT("K2Node", "SpawnActorUnknown_Title", "SpawnActor");
|
|
}
|
|
else if (CachedNodeTitle.IsOutOfDate(this))
|
|
{
|
|
FFormatNamedArguments Args;
|
|
Args.Add(TEXT("ActorName"), FText::FromString(BlueprintPin->DefaultObject->GetName()));
|
|
// FText::Format() is slow, so we cache this to save on performance
|
|
CachedNodeTitle.SetCachedText(FText::Format(NSLOCTEXT("K2Node", "SpawnActor", "SpawnActor {ActorName}"), Args), this);
|
|
}
|
|
return CachedNodeTitle;
|
|
}
|
|
|
|
bool UK2Node_SpawnActor::IsCompatibleWithGraph(const UEdGraph* TargetGraph) const
|
|
{
|
|
UBlueprint* Blueprint = FBlueprintEditorUtils::FindBlueprintForGraph(TargetGraph);
|
|
return Super::IsCompatibleWithGraph(TargetGraph) && (!Blueprint || FBlueprintEditorUtils::FindUserConstructionScript(Blueprint) != TargetGraph);
|
|
}
|
|
|
|
FNodeHandlingFunctor* UK2Node_SpawnActor::CreateNodeHandler(FKismetCompilerContext& CompilerContext) const
|
|
{
|
|
return new FNodeHandlingFunctor(CompilerContext);
|
|
}
|
|
|
|
void UK2Node_SpawnActor::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph)
|
|
{
|
|
Super::ExpandNode(CompilerContext, SourceGraph);
|
|
|
|
static FName BeginSpawningBlueprintFuncName = GET_FUNCTION_NAME_CHECKED(UGameplayStatics, BeginSpawningActorFromBlueprint);
|
|
static FName BlueprintParamName(TEXT("Blueprint"));
|
|
static FName WorldContextParamName(TEXT("WorldContextObject"));
|
|
|
|
static FName FinishSpawningFuncName = GET_FUNCTION_NAME_CHECKED(UGameplayStatics, FinishSpawningActor);
|
|
static FName ActorParamName(TEXT("Actor"));
|
|
static FName TransformParamName(TEXT("SpawnTransform"));
|
|
static FName NoCollisionFailParamName(TEXT("bNoCollisionFail"));
|
|
|
|
static FName ObjectParamName(TEXT("Object"));
|
|
static FName ValueParamName(TEXT("Value"));
|
|
static FName PropertyNameParamName(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(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;
|
|
}
|
|
|
|
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 = 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.IsArray())
|
|
{
|
|
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.ToString();
|
|
|
|
// 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.IsArray())
|
|
{
|
|
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();
|
|
}
|
|
|
|
bool UK2Node_SpawnActor::HasExternalDependencies(TArray<class UStruct*>* OptionalOutput) const
|
|
{
|
|
UClass* SourceClass = GetClassToSpawn();
|
|
const UBlueprint* SourceBlueprint = GetBlueprint();
|
|
const bool bResult = (SourceClass != NULL) && (SourceClass->ClassGeneratedBy.Get() != SourceBlueprint);
|
|
if (bResult && OptionalOutput)
|
|
{
|
|
OptionalOutput->AddUnique(SourceClass);
|
|
}
|
|
const bool bSuperResult = Super::HasExternalDependencies(OptionalOutput);
|
|
return bSuperResult || bResult;
|
|
}
|
|
|
|
void UK2Node_SpawnActor::GetNodeAttributes( TArray<TKeyValuePair<FString, FString>>& OutNodeAttributes ) const
|
|
{
|
|
UClass* ClassToSpawn = GetClassToSpawn();
|
|
const FString ClassToSpawnStr = ClassToSpawn ? ClassToSpawn->GetName() : TEXT( "InvalidClass" );
|
|
OutNodeAttributes.Add( TKeyValuePair<FString, FString>( TEXT( "Type" ), TEXT( "SpawnActor" ) ));
|
|
OutNodeAttributes.Add( TKeyValuePair<FString, FString>( TEXT( "Class" ), GetClass()->GetName() ));
|
|
OutNodeAttributes.Add( TKeyValuePair<FString, FString>( TEXT( "Name" ), GetName() ));
|
|
OutNodeAttributes.Add( TKeyValuePair<FString, FString>( TEXT( "ActorClass" ), ClassToSpawnStr ));
|
|
}
|
|
|
|
bool UK2Node_SpawnActor::IsDeprecated() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
FEdGraphNodeDeprecationResponse UK2Node_SpawnActor::GetDeprecationResponse(EEdGraphNodeDeprecationType DeprecationType) const
|
|
{
|
|
FEdGraphNodeDeprecationResponse Response = Super::GetDeprecationResponse(DeprecationType);
|
|
if (DeprecationType == EEdGraphNodeDeprecationType::NodeTypeIsDeprecated)
|
|
{
|
|
Response.MessageType = EEdGraphNodeDeprecationMessageType::None;
|
|
Response.MessageText = LOCTEXT("SpawnActorNodeOnlyDefaultBlueprint_Deprecatio", "Spawn Actor @@ is DEPRECATED and should be replaced by SpawnActorFromClass");
|
|
}
|
|
|
|
return Response;
|
|
}
|
|
|
|
FSlateIcon UK2Node_SpawnActor::GetIconAndTint(FLinearColor& OutColor) const
|
|
{
|
|
static FSlateIcon Icon(FAppStyle::GetAppStyleSetName(), "GraphEditor.SpawnActor_16x");
|
|
return Icon;
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE
|