You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#lockdown Nick.Penwarden #rb none ========================== MAJOR FEATURES + CHANGES ========================== Change 3209340 on 2016/11/23 by Ben.Marsh Convert UE4 codebase to an "include what you use" model - where every header just includes the dependencies it needs, rather than every source file including large monolithic headers like Engine.h and UnrealEd.h. Measured full rebuild times around 2x faster using XGE on Windows, and improvements of 25% or more for incremental builds and full rebuilds on most other platforms. * Every header now includes everything it needs to compile. * There's a CoreMinimal.h header that gets you a set of ubiquitous types from Core (eg. FString, FName, TArray, FVector, etc...). Most headers now include this first. * There's a CoreTypes.h header that sets up primitive UE4 types and build macros (int32, PLATFORM_WIN64, etc...). All headers in Core include this first, as does CoreMinimal.h. * Every .cpp file includes its matching .h file first. * This helps validate that each header is including everything it needs to compile. * No engine code includes a monolithic header such as Engine.h or UnrealEd.h any more. * You will get a warning if you try to include one of these from the engine. They still exist for compatibility with game projects and do not produce warnings when included there. * There have only been minor changes to our internal games down to accommodate these changes. The intent is for this to be as seamless as possible. * No engine code explicitly includes a precompiled header any more. * We still use PCHs, but they're force-included on the compiler command line by UnrealBuildTool instead. This lets us tune what they contain without breaking any existing include dependencies. * PCHs are generated by a tool to get a statistical amount of coverage for the source files using it, and I've seeded the new shared PCHs to contain any header included by > 15% of source files. Tool used to generate this transform is at Engine\Source\Programs\IncludeTool. [CL 3209342 by Ben Marsh in Main branch]
554 lines
19 KiB
C++
554 lines
19 KiB
C++
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
|
|
|
|
|
|
#include "K2Node_FunctionEntry.h"
|
|
#include "Engine/Blueprint.h"
|
|
#include "UObject/UnrealType.h"
|
|
#include "UObject/BlueprintsObjectVersion.h"
|
|
#include "UObject/StructOnScope.h"
|
|
#include "Engine/UserDefinedStruct.h"
|
|
#include "EdGraph/EdGraphSchema.h"
|
|
#include "EdGraphSchema_K2.h"
|
|
#include "K2Node_CallFunction.h"
|
|
#include "K2Node_MakeArray.h"
|
|
#include "K2Node_VariableSet.h"
|
|
#include "Kismet2/BlueprintEditorUtils.h"
|
|
#include "EdGraphUtilities.h"
|
|
#include "BPTerminal.h"
|
|
#include "UObject/PropertyPortFlags.h"
|
|
#include "KismetCompilerMisc.h"
|
|
#include "KismetCompiler.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "K2Node_FunctionEntry"
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// FKCHandler_FunctionEntry
|
|
|
|
class FKCHandler_FunctionEntry : public FNodeHandlingFunctor
|
|
{
|
|
public:
|
|
FKCHandler_FunctionEntry(FKismetCompilerContext& InCompilerContext)
|
|
: FNodeHandlingFunctor(InCompilerContext)
|
|
{
|
|
}
|
|
|
|
void RegisterFunctionInput(FKismetFunctionContext& Context, UEdGraphPin* Net, UFunction* Function)
|
|
{
|
|
// This net is a parameter into the function
|
|
FBPTerminal* Term = new (Context.Parameters) FBPTerminal();
|
|
Term->CopyFromPin(Net, Net->PinName);
|
|
|
|
// Flag pass by reference parameters specially
|
|
//@TODO: Still doesn't handle/allow users to declare new pass by reference, this only helps inherited functions
|
|
if( Function )
|
|
{
|
|
if (UProperty* ParentProperty = FindField<UProperty>(Function, FName(*(Net->PinName))))
|
|
{
|
|
if (ParentProperty->HasAnyPropertyFlags(CPF_ReferenceParm))
|
|
{
|
|
Term->bPassedByReference = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Context.NetMap.Add(Net, Term);
|
|
}
|
|
|
|
virtual void RegisterNets(FKismetFunctionContext& Context, UEdGraphNode* Node) override
|
|
{
|
|
UK2Node_FunctionEntry* EntryNode = CastChecked<UK2Node_FunctionEntry>(Node);
|
|
|
|
UFunction* Function = FindField<UFunction>(EntryNode->SignatureClass, EntryNode->SignatureName);
|
|
// if this function has a predefined signature (like for inherited/overridden
|
|
// functions), then we want to make sure to account for the output
|
|
// parameters - this is normally handled by the FunctionResult node, but
|
|
// we're not guaranteed that one is connected to the entry node
|
|
if (Function && Function->HasAnyFunctionFlags(FUNC_HasOutParms))
|
|
{
|
|
const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
|
|
|
|
for (TFieldIterator<UProperty> ParamIt(Function, EFieldIteratorFlags::ExcludeSuper); ParamIt; ++ParamIt)
|
|
{
|
|
UProperty* ParamProperty = *ParamIt;
|
|
|
|
// mirrored from UK2Node_FunctionResult::CreatePinsForFunctionEntryExit()
|
|
const bool bIsFunctionInput = !ParamProperty->HasAnyPropertyFlags(CPF_OutParm) || ParamProperty->HasAnyPropertyFlags(CPF_ReferenceParm);
|
|
if (bIsFunctionInput)
|
|
{
|
|
//
|
|
continue;
|
|
}
|
|
|
|
FEdGraphPinType ParamType;
|
|
if (K2Schema->ConvertPropertyToPinType(ParamProperty, ParamType))
|
|
{
|
|
FString ParamName = ParamProperty->GetName();
|
|
|
|
bool bTermExists = false;
|
|
// check to see if this terminal already exists (most
|
|
// likely added by a FunctionResult node) - if so, then
|
|
// we don't need to add it ourselves
|
|
for (const FBPTerminal& ResultTerm : Context.Results)
|
|
{
|
|
if (ResultTerm.Name == ParamName && ResultTerm.Type == ParamType)
|
|
{
|
|
bTermExists = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!bTermExists)
|
|
{
|
|
// create a terminal that represents a output param
|
|
// for this function; if there is a FunctionResult
|
|
// node wired into our function graph, know that it
|
|
// will first check to see if this already exists
|
|
// for it to use (rather than creating one of its own)
|
|
FBPTerminal* ResultTerm = new (Context.Results) FBPTerminal();
|
|
ResultTerm->Name = ParamName;
|
|
|
|
ResultTerm->Type = ParamType;
|
|
ResultTerm->bPassedByReference = ParamType.bIsReference;
|
|
ResultTerm->SetContextTypeStruct(ParamType.PinCategory == UEdGraphSchema_K2::PC_Struct && Cast<UScriptStruct>(ParamType.PinSubCategoryObject.Get()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (UEdGraphPin* Pin : Node->Pins)
|
|
{
|
|
if (Pin->ParentPin == nullptr && !CompilerContext.GetSchema()->IsMetaPin(*Pin))
|
|
{
|
|
UEdGraphPin* Net = FEdGraphUtilities::GetNetFromPin(Pin);
|
|
|
|
if (Context.NetMap.Find(Net) == NULL)
|
|
{
|
|
// New net, resolve the term that will be used to construct it
|
|
FBPTerminal* Term = NULL;
|
|
|
|
check(Net->Direction == EGPD_Output);
|
|
|
|
RegisterFunctionInput(Context, Pin, Function);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
virtual void Compile(FKismetFunctionContext& Context, UEdGraphNode* Node) override
|
|
{
|
|
UK2Node_FunctionEntry* EntryNode = CastChecked<UK2Node_FunctionEntry>(Node);
|
|
//check(EntryNode->SignatureName != NAME_None);
|
|
if (EntryNode->SignatureName == CompilerContext.GetSchema()->FN_ExecuteUbergraphBase)
|
|
{
|
|
UEdGraphPin* EntryPointPin = Node->FindPin(CompilerContext.GetSchema()->PN_EntryPoint);
|
|
FBPTerminal** pTerm = Context.NetMap.Find(EntryPointPin);
|
|
if ((EntryPointPin != NULL) && (pTerm != NULL))
|
|
{
|
|
FBlueprintCompiledStatement& ComputedGotoStatement = Context.AppendStatementForNode(Node);
|
|
ComputedGotoStatement.Type = KCST_ComputedGoto;
|
|
ComputedGotoStatement.LHS = *pTerm;
|
|
}
|
|
else
|
|
{
|
|
CompilerContext.MessageLog.Error(*LOCTEXT("NoEntryPointPin_Error", "Expected a pin named EntryPoint on @@").ToString(), Node);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Generate the output impulse from this node
|
|
GenerateSimpleThenGoto(Context, *Node);
|
|
}
|
|
}
|
|
};
|
|
|
|
struct FFunctionEntryHelper
|
|
{
|
|
static const FString& GetWorldContextPinName()
|
|
{
|
|
static const FString WorldContextPinName(TEXT("__WorldContext"));
|
|
return WorldContextPinName;
|
|
}
|
|
|
|
static bool RequireWorldContextParameter(const UK2Node_FunctionEntry* Node)
|
|
{
|
|
const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
|
|
return K2Schema->IsStaticFunctionGraph(Node->GetGraph());
|
|
}
|
|
};
|
|
|
|
UK2Node_FunctionEntry::UK2Node_FunctionEntry(const FObjectInitializer& ObjectInitializer)
|
|
: Super(ObjectInitializer)
|
|
{
|
|
// Enforce const-correctness by default
|
|
bEnforceConstCorrectness = true;
|
|
}
|
|
|
|
void UK2Node_FunctionEntry::Serialize(FArchive& Ar)
|
|
{
|
|
Super::Serialize(Ar);
|
|
|
|
Ar.UsingCustomVersion(FBlueprintsObjectVersion::GUID);
|
|
|
|
if (Ar.IsLoading())
|
|
{
|
|
if (Ar.UE4Ver() < VER_UE4_BLUEPRINT_ENFORCE_CONST_IN_FUNCTION_OVERRIDES)
|
|
{
|
|
// Allow legacy implementations to violate const-correctness
|
|
bEnforceConstCorrectness = false;
|
|
}
|
|
|
|
if (Ar.CustomVer(FBlueprintsObjectVersion::GUID) < FBlueprintsObjectVersion::CleanBlueprintFunctionFlags)
|
|
{
|
|
// Flags we explicitly use ExtraFlags for (at the time this fix was made):
|
|
// FUNC_Public, FUNC_Protected, FUNC_Private,
|
|
// FUNC_Static, FUNC_Const,
|
|
// FUNC_BlueprintPure, FUNC_BlueprintCallable, FUNC_BlueprintEvent, FUNC_BlueprintAuthorityOnly,
|
|
// FUNC_Net, FUNC_NetMulticast, FUNC_NetServer, FUNC_NetClient, FUNC_NetReliable
|
|
//
|
|
// FUNC_Exec, FUNC_Event, & FUNC_BlueprintCosmetic are all inherited
|
|
// in FKismetCompilerContext::PrecompileFunction()
|
|
static const uint32 InvalidExtraFlagsMask = FUNC_Final | FUNC_RequiredAPI | FUNC_BlueprintCosmetic |
|
|
FUNC_NetRequest | FUNC_Exec | FUNC_Native | FUNC_Event | FUNC_NetResponse | FUNC_MulticastDelegate |
|
|
FUNC_Delegate | FUNC_HasOutParms | FUNC_HasDefaults | FUNC_DLLImport | FUNC_NetValidate;
|
|
ExtraFlags &= ~InvalidExtraFlagsMask;
|
|
}
|
|
}
|
|
}
|
|
|
|
FText UK2Node_FunctionEntry::GetNodeTitle(ENodeTitleType::Type TitleType) const
|
|
{
|
|
UEdGraph* Graph = GetGraph();
|
|
FGraphDisplayInfo DisplayInfo;
|
|
Graph->GetSchema()->GetGraphDisplayInformation(*Graph, DisplayInfo);
|
|
|
|
return DisplayInfo.DisplayName;
|
|
}
|
|
|
|
void UK2Node_FunctionEntry::AllocateDefaultPins()
|
|
{
|
|
const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
|
|
CreatePin(EGPD_Output, K2Schema->PC_Exec, TEXT(""), NULL, false, false, K2Schema->PN_Then);
|
|
|
|
UFunction* Function = FindField<UFunction>(SignatureClass, SignatureName);
|
|
|
|
if (Function == nullptr)
|
|
{
|
|
Function = FindDelegateSignature(SignatureName);
|
|
}
|
|
|
|
if (Function != NULL)
|
|
{
|
|
CreatePinsForFunctionEntryExit(Function, /*bIsFunctionEntry=*/ true);
|
|
}
|
|
|
|
Super::AllocateDefaultPins();
|
|
|
|
if (FFunctionEntryHelper::RequireWorldContextParameter(this)
|
|
&& ensure(!FindPin(FFunctionEntryHelper::GetWorldContextPinName())))
|
|
{
|
|
UEdGraphPin* WorldContextPin = CreatePin(
|
|
EGPD_Output,
|
|
K2Schema->PC_Object,
|
|
FString(),
|
|
UObject::StaticClass(),
|
|
false,
|
|
false,
|
|
FFunctionEntryHelper::GetWorldContextPinName());
|
|
WorldContextPin->bHidden = true;
|
|
}
|
|
}
|
|
|
|
UEdGraphPin* UK2Node_FunctionEntry::GetAutoWorldContextPin() const
|
|
{
|
|
return FindPin(FFunctionEntryHelper::GetWorldContextPinName());
|
|
}
|
|
|
|
void UK2Node_FunctionEntry::RemoveOutputPin(UEdGraphPin* PinToRemove)
|
|
{
|
|
UK2Node_FunctionEntry* OwningSeq = Cast<UK2Node_FunctionEntry>( PinToRemove->GetOwningNode() );
|
|
if (OwningSeq)
|
|
{
|
|
PinToRemove->MarkPendingKill();
|
|
OwningSeq->Pins.Remove(PinToRemove);
|
|
}
|
|
}
|
|
|
|
bool UK2Node_FunctionEntry::CanCreateUserDefinedPin(const FEdGraphPinType& InPinType, EEdGraphPinDirection InDesiredDirection, FText& OutErrorMessage)
|
|
{
|
|
bool bResult = Super::CanCreateUserDefinedPin(InPinType, InDesiredDirection, OutErrorMessage);
|
|
if (bResult)
|
|
{
|
|
if(InDesiredDirection == EGPD_Input)
|
|
{
|
|
OutErrorMessage = LOCTEXT("AddInputPinError", "Cannot add input pins to function entry node!");
|
|
bResult = false;
|
|
}
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
UEdGraphPin* UK2Node_FunctionEntry::CreatePinFromUserDefinition(const TSharedPtr<FUserPinInfo> NewPinInfo)
|
|
{
|
|
// Make sure that if this is an exec node we are allowed one.
|
|
const UEdGraphSchema_K2* Schema = GetDefault<UEdGraphSchema_K2>();
|
|
if (NewPinInfo->PinType.PinCategory == Schema->PC_Exec && !CanModifyExecutionWires())
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
UEdGraphPin* NewPin = CreatePin(EGPD_Output, NewPinInfo->PinType, NewPinInfo->PinName);
|
|
NewPin->DefaultValue = NewPin->AutogeneratedDefaultValue = NewPinInfo->PinDefaultValue;
|
|
return NewPin;
|
|
}
|
|
|
|
FNodeHandlingFunctor* UK2Node_FunctionEntry::CreateNodeHandler(FKismetCompilerContext& CompilerContext) const
|
|
{
|
|
return new FKCHandler_FunctionEntry(CompilerContext);
|
|
}
|
|
|
|
void UK2Node_FunctionEntry::GetRedirectPinNames(const UEdGraphPin& Pin, TArray<FString>& RedirectPinNames) const
|
|
{
|
|
Super::GetRedirectPinNames(Pin, RedirectPinNames);
|
|
|
|
if(RedirectPinNames.Num() > 0)
|
|
{
|
|
const FString& OldPinName = RedirectPinNames[0];
|
|
|
|
|
|
// first add functionname.param
|
|
RedirectPinNames.Add(FString::Printf(TEXT("%s.%s"), *SignatureName.ToString(), *OldPinName));
|
|
// if there is class, also add an option for class.functionname.param
|
|
if(SignatureClass!=NULL)
|
|
{
|
|
RedirectPinNames.Add(FString::Printf(TEXT("%s.%s.%s"), *SignatureClass->GetName(), *SignatureName.ToString(), *OldPinName));
|
|
}
|
|
}
|
|
}
|
|
|
|
bool UK2Node_FunctionEntry::IsDeprecated() const
|
|
{
|
|
if (UFunction* const Function = FindField<UFunction>(SignatureClass, SignatureName))
|
|
{
|
|
return Function->HasMetaData(FBlueprintMetadata::MD_DeprecatedFunction);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
FString UK2Node_FunctionEntry::GetDeprecationMessage() const
|
|
{
|
|
if (UFunction* const Function = FindField<UFunction>(SignatureClass, SignatureName))
|
|
{
|
|
if (Function->HasMetaData(FBlueprintMetadata::MD_DeprecationMessage))
|
|
{
|
|
return FString::Printf(TEXT("%s %s"), *LOCTEXT("FunctionDeprecated_Warning", "@@ is deprecated;").ToString(), *Function->GetMetaData(FBlueprintMetadata::MD_DeprecationMessage));
|
|
}
|
|
}
|
|
|
|
return Super::GetDeprecationMessage();
|
|
}
|
|
|
|
FText UK2Node_FunctionEntry::GetTooltipText() const
|
|
{
|
|
UFunction* Function = FindField<UFunction>(SignatureClass, SignatureName);
|
|
if (Function)
|
|
{
|
|
return FText::FromString(UK2Node_CallFunction::GetDefaultTooltipForFunction(Function));
|
|
}
|
|
return Super::GetTooltipText();
|
|
}
|
|
|
|
int32 UK2Node_FunctionEntry::GetFunctionFlags() const
|
|
{
|
|
int32 ReturnFlags = 0;
|
|
|
|
UClass* ClassToLookup = SignatureClass;
|
|
|
|
if (SignatureClass && SignatureClass->ClassGeneratedBy)
|
|
{
|
|
UBlueprint* GeneratingBP = CastChecked<UBlueprint>(SignatureClass->ClassGeneratedBy);
|
|
ClassToLookup = GeneratingBP->SkeletonGeneratedClass;
|
|
}
|
|
|
|
UFunction* Function = FindField<UFunction>(ClassToLookup, SignatureName);
|
|
if (Function)
|
|
{
|
|
ReturnFlags = Function->FunctionFlags;
|
|
}
|
|
return ReturnFlags | ExtraFlags;
|
|
}
|
|
|
|
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());
|
|
|
|
// When regenerating on load, we may need to import text on certain properties to force load the assets
|
|
TSharedPtr<FStructOnScope> LocalVarData;
|
|
if (Function && CompilerContext.Blueprint->bIsRegeneratingOnLoad)
|
|
{
|
|
if (Function->GetStructureSize() > 0 || !ensure(Function->PropertyLink == nullptr))
|
|
{
|
|
LocalVarData = MakeShareable(new FStructOnScope(Function));
|
|
}
|
|
}
|
|
|
|
for (TFieldIterator<UProperty> It(Function); It; ++It)
|
|
{
|
|
if (const UProperty* Property = *It)
|
|
{
|
|
const UStructProperty* PotentialUDSProperty = Cast<const UStructProperty>(Property);
|
|
//UDS requires default data even when the LocalVariable value is empty
|
|
const bool bUDSProperty = PotentialUDSProperty && Cast<const UUserDefinedStruct>(PotentialUDSProperty->Struct);
|
|
|
|
for (auto& LocalVar : LocalVariables)
|
|
{
|
|
if (LocalVar.VarName == Property->GetFName() && (bUDSProperty || !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
|
|
{
|
|
if (CompilerContext.Blueprint->bIsRegeneratingOnLoad)
|
|
{
|
|
// When regenerating on load, we want to force load assets referenced by local variables.
|
|
// This functionality is already handled when generating Terms in the Kismet Compiler for Arrays and Structs, so we do not have to worry about them.
|
|
if (LocalVar.VarType.PinCategory == Schema->PC_Object || LocalVar.VarType.PinCategory == Schema->PC_Class || LocalVar.VarType.PinCategory == Schema->PC_Interface)
|
|
{
|
|
FBlueprintEditorUtils::PropertyValueFromString(Property, LocalVar.DefaultValue, LocalVarData->GetStructMemory());
|
|
}
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void RefreshUDSValuesStoredAsString(const FEdGraphPinType& VarType, FString& Value)
|
|
{
|
|
if (!Value.IsEmpty() && VarType.PinCategory == UEdGraphSchema_K2::PC_Struct)
|
|
{
|
|
UUserDefinedStruct* UDS = Cast<UUserDefinedStruct>(VarType.PinSubCategoryObject.Get());
|
|
if (UDS)
|
|
{
|
|
FStructOnScope StructInstance(UDS);
|
|
UDS->InitializeDefaultValue(StructInstance.GetStructMemory());
|
|
UDS->ImportText(*Value, StructInstance.GetStructMemory(), nullptr, PPF_None, GLog, FString());
|
|
|
|
Value.Reset();
|
|
FStructOnScope DefaultStructInstance(UDS);
|
|
UDS->InitializeDefaultValue(DefaultStructInstance.GetStructMemory());
|
|
UDS->ExportText(Value, StructInstance.GetStructMemory(), DefaultStructInstance.GetStructMemory(), nullptr, PPF_None, nullptr);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UK2Node_FunctionEntry::PostReconstructNode()
|
|
{
|
|
Super::PostReconstructNode();
|
|
|
|
UBlueprint* Blueprint = GetBlueprint();
|
|
|
|
// We want to refresh old UDS default values of local variables. It's enough to do this once.
|
|
if (Blueprint && Blueprint->bIsRegeneratingOnLoad)
|
|
{
|
|
for (FBPVariableDescription& LocalVariable : LocalVariables)
|
|
{
|
|
RefreshUDSValuesStoredAsString(LocalVariable.VarType, LocalVariable.DefaultValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#undef LOCTEXT_NAMESPACE
|