2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
# include "BlueprintGraphPrivatePCH.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 ) ;
}
2014-06-13 06:14:46 -04:00
virtual void RegisterNets ( FKismetFunctionContext & Context , UEdGraphNode * Node ) override
2014-03-14 14:13:41 -04:00
{
UK2Node_FunctionEntry * EntryNode = CastChecked < UK2Node_FunctionEntry > ( Node ) ;
UFunction * Function = FindField < UFunction > ( EntryNode - > SignatureClass , EntryNode - > SignatureName ) ;
2014-06-18 16:22:49 -04:00
for ( UEdGraphPin * Pin : Node - > Pins )
2014-03-14 14:13:41 -04:00
{
2014-06-18 16:22:49 -04:00
if ( Pin - > ParentPin = = nullptr & & ! CompilerContext . GetSchema ( ) - > IsMetaPin ( * Pin ) )
2014-03-14 14:13:41 -04:00
{
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 ) ;
}
}
}
}
2014-06-13 06:14:46 -04:00
virtual void Compile ( FKismetFunctionContext & Context , UEdGraphNode * Node ) override
2014-03-14 14:13:41 -04:00
{
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 ) ;
}
}
} ;
2014-04-30 13:08:46 -04:00
struct FFunctionEntryHelper
{
static const FString & GetWorldContextPinName ( )
{
static const FString WorldContextPinName ( TEXT ( " __WorldContext " ) ) ;
return WorldContextPinName ;
}
static bool RequireWorldContextParameter ( const UK2Node_FunctionEntry * Node )
{
[UE-2345] BP - enforce const-correctness in native const class method overrides
this change introduces enforcement of 'const-correctness' into implemented function graphs.
summary:
if you have a function declared in C++ like this:
UFUNCTION(BlueprintImplementableEvent)
int32 MyFunctionThatReturnsSomeValue() const;
if you implement that (BPIE) function in a Blueprint that's parented to that native class, it will now be flagged as 'const'. this makes any properties of 'self' read-only within the context of that graph, which means the compiler will emit an error if you try to set a property or otherwise call a non-const, non-static function with 'self' as the target.
if there happens to already be an implemented const function in a Blueprint that was in place prior to this change, the compiler will emit a warning instead of an error, in order to allow existing Blueprints that may currently be "violating" const within the context of a const BPIE function to still compile, while still alerting to issues that should probably be addressed.
notes:
1) this also applies to BlueprintNativeEvent (BPNE) implementations, and also when implementing BPIE/BPNE interface methods that are also declared as const
2) a const BPIE/BPNE function with no return value and no output parameters will be implemented as a "normal" impure function, and not as an event as in the non-const case
3) a const BPIE/BPNE function with a return value and/or output parameters will currently be implemented as a pure function, regardless of whether or not BlueprintCallable is specified
4) this CL also retains some consolidation of static function validation code that i had previously done, mostly to allow static functions to more easily be whitelisted for const function graphs
#codereview Nick.Whiting, Michael.Noland
[CL 2368059 by Phillip Kavan in Main branch]
2014-11-21 17:47:17 -05:00
const UEdGraphSchema_K2 * K2Schema = GetDefault < UEdGraphSchema_K2 > ( ) ;
return K2Schema - > IsStaticFunctionGraph ( Node - > GetGraph ( ) ) ;
2014-04-30 13:08:46 -04:00
}
} ;
2014-03-14 14:13:41 -04:00
2014-10-14 10:29:11 -04:00
UK2Node_FunctionEntry : : UK2Node_FunctionEntry ( const FObjectInitializer & ObjectInitializer )
: Super ( ObjectInitializer )
2014-03-14 14:13:41 -04:00
{
[UE-2345] BP - enforce const-correctness in native const class method overrides
this change introduces enforcement of 'const-correctness' into implemented function graphs.
summary:
if you have a function declared in C++ like this:
UFUNCTION(BlueprintImplementableEvent)
int32 MyFunctionThatReturnsSomeValue() const;
if you implement that (BPIE) function in a Blueprint that's parented to that native class, it will now be flagged as 'const'. this makes any properties of 'self' read-only within the context of that graph, which means the compiler will emit an error if you try to set a property or otherwise call a non-const, non-static function with 'self' as the target.
if there happens to already be an implemented const function in a Blueprint that was in place prior to this change, the compiler will emit a warning instead of an error, in order to allow existing Blueprints that may currently be "violating" const within the context of a const BPIE function to still compile, while still alerting to issues that should probably be addressed.
notes:
1) this also applies to BlueprintNativeEvent (BPNE) implementations, and also when implementing BPIE/BPNE interface methods that are also declared as const
2) a const BPIE/BPNE function with no return value and no output parameters will be implemented as a "normal" impure function, and not as an event as in the non-const case
3) a const BPIE/BPNE function with a return value and/or output parameters will currently be implemented as a pure function, regardless of whether or not BlueprintCallable is specified
4) this CL also retains some consolidation of static function validation code that i had previously done, mostly to allow static functions to more easily be whitelisted for const function graphs
#codereview Nick.Whiting, Michael.Noland
[CL 2368059 by Phillip Kavan in Main branch]
2014-11-21 17:47:17 -05:00
// Enforce const-correctness by default
bEnforceConstCorrectness = true ;
}
void UK2Node_FunctionEntry : : Serialize ( FArchive & Ar )
{
Super : : Serialize ( Ar ) ;
if ( Ar . IsLoading ( ) )
{
if ( Ar . UE4Ver ( ) < VER_UE4_BLUEPRINT_ENFORCE_CONST_IN_FUNCTION_OVERRIDES )
{
// Allow legacy implementations to violate const-correctness
bEnforceConstCorrectness = false ;
}
}
2014-03-14 14:13:41 -04:00
}
2014-04-23 18:30:37 -04:00
FText UK2Node_FunctionEntry : : GetNodeTitle ( ENodeTitleType : : Type TitleType ) const
2014-03-14 14:13:41 -04:00
{
UEdGraph * Graph = GetGraph ( ) ;
FGraphDisplayInfo DisplayInfo ;
Graph - > GetSchema ( ) - > GetGraphDisplayInformation ( * Graph , DisplayInfo ) ;
2014-04-23 18:30:37 -04:00
return DisplayInfo . DisplayName ;
}
2014-03-14 14:13:41 -04:00
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 ) ;
2015-01-20 09:33:54 -05:00
if ( Function = = nullptr )
{
Function = FindDelegateSignature ( SignatureName ) ;
}
2014-03-14 14:13:41 -04:00
if ( Function ! = NULL )
{
CreatePinsForFunctionEntryExit ( Function , /*bIsFunctionEntry=*/ true ) ;
}
Super : : AllocateDefaultPins ( ) ;
2014-04-30 13:08:46 -04:00
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 ;
}
}
2014-04-30 15:54:13 -04:00
UEdGraphPin * UK2Node_FunctionEntry : : GetAutoWorldContextPin ( ) const
2014-04-30 13:08:46 -04:00
{
return FFunctionEntryHelper : : RequireWorldContextParameter ( this ) ? FindPin ( FFunctionEntryHelper : : GetWorldContextPinName ( ) ) : NULL ;
2014-03-14 14:13:41 -04:00
}
2014-04-30 15:54:13 -04:00
void UK2Node_FunctionEntry : : RemoveUnnecessaryAutoWorldContext ( )
{
2014-10-17 07:57:28 -04:00
auto WorldContextPin = GetAutoWorldContextPin ( ) ;
if ( WorldContextPin )
{
if ( ! WorldContextPin - > LinkedTo . Num ( ) )
{
Pins . Remove ( WorldContextPin ) ;
}
}
2014-04-30 15:54:13 -04:00
}
2014-03-14 14:13:41 -04:00
void UK2Node_FunctionEntry : : RemoveOutputPin ( UEdGraphPin * PinToRemove )
{
UK2Node_FunctionEntry * OwningSeq = Cast < UK2Node_FunctionEntry > ( PinToRemove - > GetOwningNode ( ) ) ;
if ( OwningSeq )
{
PinToRemove - > BreakAllPinLinks ( ) ;
OwningSeq - > Pins . Remove ( PinToRemove ) ;
}
}
2015-03-31 10:32:10 -04:00
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 ;
}
2014-03-14 14:13:41 -04:00
UEdGraphPin * UK2Node_FunctionEntry : : CreatePinFromUserDefinition ( const TSharedPtr < FUserPinInfo > NewPinInfo )
{
2015-03-31 10:32:10 -04:00
// 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 ;
}
2014-03-14 14:13:41 -04:00
UEdGraphPin * NewPin = CreatePin (
EGPD_Output ,
NewPinInfo - > PinType . PinCategory ,
NewPinInfo - > PinType . PinSubCategory ,
NewPinInfo - > PinType . PinSubCategoryObject . Get ( ) ,
NewPinInfo - > PinType . bIsArray ,
NewPinInfo - > PinType . bIsReference ,
NewPinInfo - > PinName ) ;
NewPin - > DefaultValue = NewPin - > AutogeneratedDefaultValue = NewPinInfo - > PinDefaultValue ;
return NewPin ;
}
FNodeHandlingFunctor * UK2Node_FunctionEntry : : CreateNodeHandler ( FKismetCompilerContext & CompilerContext ) const
{
return new FKCHandler_FunctionEntry ( CompilerContext ) ;
}
2014-07-14 18:06:16 -04:00
void UK2Node_FunctionEntry : : GetRedirectPinNames ( const UEdGraphPin & Pin , TArray < FString > & RedirectPinNames ) const
{
Super : : GetRedirectPinNames ( Pin , RedirectPinNames ) ;
2014-03-14 14:13:41 -04:00
2014-07-14 18:06:16 -04:00
if ( RedirectPinNames . Num ( ) > 0 )
{
2014-10-01 14:45:23 -04:00
const FString & OldPinName = RedirectPinNames [ 0 ] ;
2014-07-14 18:06:16 -04:00
// 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 ) ) ;
}
}
}
2014-03-14 14:13:41 -04:00
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 ( ) ;
}
2014-12-10 10:57:36 -05:00
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 ArrayHelper ( ArrayProperty , StructData - > GetStructMemory ( ) ) ;
FScriptArrayHelper 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 ;
2014-12-10 12:38:55 -05:00
FBlueprintEditorUtils : : PropertyValueToString ( ArrayProperty - > Inner , PropData , DefaultValue ) ;
2014-12-10 10:57:36 -05:00
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 ) ;
}
}
}
2014-03-14 14:13:41 -04:00
# undef LOCTEXT_NAMESPACE