2014-12-15 16:01:27 -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"
2014-06-30 06:59:25 -04:00
# include "MakeStructHandler.h"
2014-09-17 14:57:06 -04:00
# include "BlueprintFieldNodeSpawner.h"
2014-07-14 12:39:28 -04:00
# include "EditorCategoryUtils.h"
2014-08-23 20:16:29 -04:00
# include "BlueprintActionDatabaseRegistrar.h"
2014-09-29 14:36:08 -04:00
# include "BlueprintActionFilter.h" // for FBlueprintActionContext
2014-03-14 14:13:41 -04:00
# define LOCTEXT_NAMESPACE "K2Node_MakeStruct"
//////////////////////////////////////////////////////////////////////////
// UK2Node_MakeStruct
2014-04-23 20:18:55 -04:00
UK2Node_MakeStruct : : FMakeStructPinManager : : FMakeStructPinManager ( const uint8 * InSampleStructMemory )
: FStructOperationOptionalPinManager ( ) , SampleStructMemory ( InSampleStructMemory )
2014-03-14 14:13:41 -04:00
{
2014-04-23 20:18:55 -04:00
}
2014-03-14 14:13:41 -04:00
2014-04-23 20:18:55 -04:00
void UK2Node_MakeStruct : : FMakeStructPinManager : : CustomizePinData ( UEdGraphPin * Pin , FName SourcePropertyName , int32 ArrayIndex , UProperty * Property ) const
{
struct FPinDefaultValueHelper
2014-03-14 14:13:41 -04:00
{
2015-04-08 14:54:45 -04:00
static void Set ( UEdGraphPin & InPin , const FString & Value , bool bIsText , bool bIsObject )
2014-03-14 14:13:41 -04:00
{
2014-05-29 16:52:50 -04:00
InPin . AutogeneratedDefaultValue = Value ;
2014-04-23 20:18:55 -04:00
if ( bIsText )
2014-03-14 14:13:41 -04:00
{
2014-05-29 16:52:50 -04:00
InPin . DefaultTextValue = FText : : FromString ( Value ) ;
2014-03-14 14:13:41 -04:00
}
2015-04-08 14:54:45 -04:00
else if ( bIsObject )
{
InPin . DefaultObject = StaticFindObject ( UObject : : StaticClass ( ) , nullptr , * Value ) ;
}
2014-04-23 20:18:55 -04:00
else
2014-06-30 06:59:25 -04:00
{
2014-05-29 16:52:50 -04:00
InPin . DefaultValue = Value ;
2014-04-23 20:18:55 -04:00
}
2014-06-30 06:59:25 -04:00
}
2014-04-23 20:18:55 -04:00
} ;
UK2Node_StructOperation : : FStructOperationOptionalPinManager : : CustomizePinData ( Pin , SourcePropertyName , ArrayIndex , Property ) ;
2014-06-30 06:59:25 -04:00
if ( Pin & & Property )
{
const UEdGraphSchema_K2 * Schema = GetDefault < UEdGraphSchema_K2 > ( ) ;
check ( Schema ) ;
2014-12-16 07:00:59 -05:00
// Should pin default value be filled as FText?
const bool bIsText = Property - > IsA < UTextProperty > ( ) ;
checkSlow ( bIsText = = ( ( Schema - > PC_Text = = Pin - > PinType . PinCategory ) & & ! Pin - > PinType . bIsArray ) ) ;
2014-04-23 20:18:55 -04:00
2015-04-08 14:54:45 -04:00
const bool bIsObject = Property - > IsA < UObjectPropertyBase > ( ) ;
checkSlow ( bIsObject = = ( ( Schema - > PC_Object = = Pin - > PinType . PinCategory | | Schema - > PC_Class = = Pin - > PinType . PinCategory ) & & ! Pin - > PinType . bIsArray ) ) ;
2014-06-30 06:59:25 -04:00
const FString & MetadataDefaultValue = Property - > GetMetaData ( TEXT ( " MakeStructureDefaultValue " ) ) ;
if ( ! MetadataDefaultValue . IsEmpty ( ) )
{
2015-04-08 14:54:45 -04:00
FPinDefaultValueHelper : : Set ( * Pin , MetadataDefaultValue , bIsText , bIsObject ) ;
2014-06-30 06:59:25 -04:00
return ;
}
2014-06-16 10:30:41 -04:00
2014-06-30 06:59:25 -04:00
if ( NULL ! = SampleStructMemory )
{
FString NewDefaultValue ;
if ( Property - > ExportText_InContainer ( 0 , NewDefaultValue , SampleStructMemory , SampleStructMemory , NULL , PPF_None ) )
2014-06-16 10:30:41 -04:00
{
2014-06-30 06:59:25 -04:00
if ( Schema - > IsPinDefaultValid ( Pin , NewDefaultValue , NULL , FText : : GetEmpty ( ) ) . IsEmpty ( ) )
2014-03-14 14:13:41 -04:00
{
2015-04-08 14:54:45 -04:00
FPinDefaultValueHelper : : Set ( * Pin , NewDefaultValue , bIsText , bIsObject ) ;
2014-06-30 06:59:25 -04:00
return ;
2014-03-14 14:13:41 -04:00
}
}
}
2014-06-30 06:59:25 -04:00
Schema - > SetPinDefaultValueBasedOnType ( Pin ) ;
2014-03-14 14:13:41 -04:00
}
2014-06-30 06:59:25 -04:00
}
2014-03-14 14:13:41 -04:00
2015-04-16 14:02:15 -04:00
static bool CanBeExposed ( const UProperty * Property , bool bIncludeEditOnly = true )
{
if ( Property )
2014-06-16 10:30:41 -04:00
{
2015-04-16 14:02:15 -04:00
const UEdGraphSchema_K2 * Schema = GetDefault < UEdGraphSchema_K2 > ( ) ;
check ( Schema ) ;
FEdGraphPinType DumbGraphPinType ;
const bool bConvertable = Schema - > ConvertPropertyToPinType ( Property , /*out*/ DumbGraphPinType ) ;
//TODO: remove CPF_Edit in a future release
const bool bVisible = ( bIncludeEditOnly ? Property - > HasAnyPropertyFlags ( CPF_BlueprintVisible | CPF_Edit ) : Property - > HasAnyPropertyFlags ( CPF_BlueprintVisible ) ) & & ! ( Property - > ArrayDim > 1 ) ;
const bool bBlueprintReadOnly = Property - > HasAllPropertyFlags ( CPF_BlueprintReadOnly ) ;
if ( bVisible & & bConvertable & & ! bBlueprintReadOnly )
{
return true ;
}
2014-06-16 10:30:41 -04:00
}
2015-04-16 14:02:15 -04:00
return false ;
}
bool UK2Node_MakeStruct : : FMakeStructPinManager : : CanTreatPropertyAsOptional ( UProperty * TestProperty ) const
{
return CanBeExposed ( TestProperty ) ;
}
2014-03-14 14:13:41 -04:00
2014-10-14 10:29:11 -04:00
UK2Node_MakeStruct : : UK2Node_MakeStruct ( const FObjectInitializer & ObjectInitializer )
: Super ( ObjectInitializer )
2014-03-14 14:13:41 -04:00
{
}
void UK2Node_MakeStruct : : AllocateDefaultPins ( )
{
const UEdGraphSchema_K2 * Schema = GetDefault < UEdGraphSchema_K2 > ( ) ;
if ( Schema & & StructType )
{
CreatePin ( EGPD_Output , Schema - > PC_Struct , TEXT ( " " ) , StructType , false , false , StructType - > GetName ( ) ) ;
{
2014-05-29 17:02:19 -04:00
FStructOnScope StructOnScope ( Cast < UScriptStruct > ( StructType ) ) ;
2014-03-14 14:13:41 -04:00
FMakeStructPinManager OptionalPinManager ( StructOnScope . GetStructMemory ( ) ) ;
OptionalPinManager . RebuildPropertyList ( ShowPinForProperties , StructType ) ;
OptionalPinManager . CreateVisiblePins ( ShowPinForProperties , StructType , EGPD_Input , this ) ;
}
// When struct has a lot of fields, mark their pins as advanced
if ( Pins . Num ( ) > 5 )
{
if ( ENodeAdvancedPins : : NoPins = = AdvancedPinDisplay )
{
AdvancedPinDisplay = ENodeAdvancedPins : : Hidden ;
}
for ( int32 PinIndex = 3 ; PinIndex < Pins . Num ( ) ; + + PinIndex )
{
if ( UEdGraphPin * EdGraphPin = Pins [ PinIndex ] )
{
EdGraphPin - > bAdvancedView = true ;
}
}
}
}
}
void UK2Node_MakeStruct : : ValidateNodeDuringCompilation ( class FCompilerResultsLog & MessageLog ) const
{
if ( ! StructType )
{
MessageLog . Error ( * LOCTEXT ( " NoStruct_Error " , " No Struct in @@ " ) . ToString ( ) , this ) ;
}
2014-08-05 14:16:02 -04:00
else
{
bool bHasAnyBlueprintVisibleProperty = false ;
for ( TFieldIterator < UProperty > It ( StructType ) ; It ; + + It )
{
const UProperty * Property = * It ;
if ( CanBeExposed ( Property ) )
{
2014-08-08 11:13:17 -04:00
const bool bIsBlueprintVisible = Property - > HasAnyPropertyFlags ( CPF_BlueprintVisible ) | | ( Property - > GetOwnerStruct ( ) & & Property - > GetOwnerStruct ( ) - > IsA < UUserDefinedStruct > ( ) ) ;
2014-08-05 14:16:02 -04:00
bHasAnyBlueprintVisibleProperty | = bIsBlueprintVisible ;
2015-03-31 20:12:31 -04:00
const UEdGraphPin * Pin = FindPin ( Property - > GetName ( ) ) ;
2014-08-05 14:16:02 -04:00
2014-08-19 15:53:29 -04:00
if ( Pin & & ! bIsBlueprintVisible )
2014-08-05 14:16:02 -04:00
{
MessageLog . Warning ( * LOCTEXT ( " PropertyIsNotBPVisible_Warning " , " @@ - the native property is not tagged as BlueprintReadWrite, the pin will be removed in a future release. " ) . ToString ( ) , Pin ) ;
}
if ( Property - > ArrayDim > 1 )
{
MessageLog . Warning ( * LOCTEXT ( " StaticArray_Warning " , " @@ - the native property is a static array, which is not supported by blueprints " ) . ToString ( ) , Pin ) ;
}
}
}
if ( ! bHasAnyBlueprintVisibleProperty )
{
MessageLog . Warning ( * LOCTEXT ( " StructHasNoBPVisibleProperties_Warning " , " @@ has no property tagged as BlueprintReadWrite. The node will be removed in a future release. " ) . ToString ( ) , this ) ;
}
}
2014-03-14 14:13:41 -04:00
}
2014-04-23 18:30:37 -04:00
FText UK2Node_MakeStruct : : GetNodeTitle ( ENodeTitleType : : Type TitleType ) const
2014-03-14 14:13:41 -04:00
{
2014-09-03 18:17:44 -04:00
if ( StructType = = nullptr )
{
return LOCTEXT ( " MakeNullStructTitle " , " Make <unknown struct> " ) ;
}
2015-04-02 11:16:23 -04:00
else if ( CachedNodeTitle . IsOutOfDate ( this ) )
2014-09-02 19:08:09 -04:00
{
FFormatNamedArguments Args ;
2014-09-03 18:17:44 -04:00
Args . Add ( TEXT ( " StructName " ) , FText : : FromName ( StructType - > GetFName ( ) ) ) ;
2014-09-02 19:08:09 -04:00
// FText::Format() is slow, so we cache this to save on performance
2015-04-02 11:16:23 -04:00
CachedNodeTitle . SetCachedText ( FText : : Format ( LOCTEXT ( " MakeNodeTitle " , " Make {StructName} " ) , Args ) , this ) ;
2014-09-02 19:08:09 -04:00
}
return CachedNodeTitle ;
2014-04-23 18:30:37 -04:00
}
2014-09-03 18:14:09 -04:00
FText UK2Node_MakeStruct : : GetTooltipText ( ) const
2014-03-14 14:13:41 -04:00
{
2014-09-03 18:17:44 -04:00
if ( StructType = = nullptr )
{
return LOCTEXT ( " MakeNullStruct_Tooltip " , " Adds a node that create an '<unknown struct>' from its members " ) ;
}
2015-04-02 11:16:23 -04:00
else if ( CachedTooltip . IsOutOfDate ( this ) )
2014-09-03 18:17:44 -04:00
{
// FText::Format() is slow, so we cache this to save on performance
2015-04-02 11:16:23 -04:00
CachedTooltip . SetCachedText ( FText : : Format (
2014-09-03 18:17:44 -04:00
LOCTEXT ( " MakeStruct_Tooltip " , " Adds a node that create a '{0}' from its members " ) ,
FText : : FromName ( StructType - > GetFName ( ) )
2015-04-02 11:16:23 -04:00
) , this ) ;
2014-09-03 18:17:44 -04:00
}
return CachedTooltip ;
2014-03-14 14:13:41 -04:00
}
FLinearColor UK2Node_MakeStruct : : GetNodeTitleColor ( ) const
{
if ( const UEdGraphSchema_K2 * K2Schema = GetDefault < UEdGraphSchema_K2 > ( ) )
{
FEdGraphPinType PinType ;
PinType . PinCategory = K2Schema - > PC_Struct ;
PinType . PinSubCategoryObject = StructType ;
return K2Schema - > GetPinTypeColor ( PinType ) ;
}
return UK2Node : : GetNodeTitleColor ( ) ;
}
2015-04-16 14:02:15 -04:00
bool UK2Node_MakeStruct : : CanBeMade ( const UScriptStruct * Struct , bool bIncludeEditOnly )
2014-03-14 14:13:41 -04:00
{
2015-04-08 14:54:45 -04:00
if ( Struct & & ! Struct - > HasMetaData ( TEXT ( " HasNativeMake " ) ) )
2014-03-14 14:13:41 -04:00
{
2015-04-16 14:02:15 -04:00
if ( UEdGraphSchema_K2 : : IsAllowableBlueprintVariableType ( Struct ) )
{
return true ;
}
2014-03-14 14:13:41 -04:00
for ( TFieldIterator < UProperty > It ( Struct ) ; It ; + + It )
{
2015-04-16 14:02:15 -04:00
if ( CanBeExposed ( * It , bIncludeEditOnly ) )
2014-03-14 14:13:41 -04:00
{
return true ;
}
}
}
return false ;
}
FNodeHandlingFunctor * UK2Node_MakeStruct : : CreateNodeHandler ( FKismetCompilerContext & CompilerContext ) const
{
return new FKCHandler_MakeStruct ( CompilerContext ) ;
}
UK2Node : : ERedirectType UK2Node_MakeStruct : : DoPinsMatchForReconstruction ( const UEdGraphPin * NewPin , int32 NewPinIndex , const UEdGraphPin * OldPin , int32 OldPinIndex ) const
{
ERedirectType Result = UK2Node : : DoPinsMatchForReconstruction ( NewPin , NewPinIndex , OldPin , OldPinIndex ) ;
2014-09-17 14:27:00 -04:00
if ( ( ERedirectType_None = = Result ) & & DoRenamedPinsMatch ( NewPin , OldPin , false ) )
{
Result = ERedirectType_Custom ;
}
else if ( ( ERedirectType_None = = Result ) & & NewPin & & OldPin )
2014-03-14 14:13:41 -04:00
{
2014-06-16 10:30:41 -04:00
if ( ( EGPD_Output = = NewPin - > Direction ) & & ( EGPD_Output = = OldPin - > Direction ) )
{
2014-06-30 06:59:25 -04:00
const UEdGraphSchema_K2 * K2Schema = GetDefault < UEdGraphSchema_K2 > ( ) ;
if ( K2Schema - > ArePinTypesCompatible ( NewPin - > PinType , OldPin - > PinType ) )
{
Result = ERedirectType_Custom ;
}
2014-06-16 10:30:41 -04:00
}
else if ( ( EGPD_Input = = NewPin - > Direction ) & & ( EGPD_Input = = OldPin - > Direction ) )
{
TMap < FName , FName > * StructRedirects = UStruct : : TaggedPropertyRedirects . Find ( StructType - > GetFName ( ) ) ;
if ( StructRedirects )
{
FName * PropertyRedirect = StructRedirects - > Find ( FName ( * OldPin - > PinName ) ) ;
if ( PropertyRedirect )
{
Result = ( ( FCString : : Stricmp ( * PropertyRedirect - > ToString ( ) , * NewPin - > PinName ) ! = 0 ) ? ERedirectType_None : ERedirectType_Name ) ;
}
}
}
2014-03-14 14:13:41 -04:00
}
return Result ;
}
2014-08-23 20:16:29 -04:00
void UK2Node_MakeStruct : : GetMenuActions ( FBlueprintActionDatabaseRegistrar & ActionRegistrar ) const
2014-07-14 12:39:28 -04:00
{
2014-09-17 14:57:06 -04:00
auto SetNodeStructLambda = [ ] ( UEdGraphNode * NewNode , UField const * /*StructField*/ , TWeakObjectPtr < UScriptStruct > NonConstStructPtr )
2014-09-10 17:09:26 -04:00
{
UK2Node_MakeStruct * MakeNode = CastChecked < UK2Node_MakeStruct > ( NewNode ) ;
2014-09-17 14:57:06 -04:00
MakeNode - > StructType = NonConstStructPtr . Get ( ) ;
2014-09-10 17:09:26 -04:00
} ;
2014-09-29 14:36:08 -04:00
auto CategoryOverrideLambda = [ ] ( FBlueprintActionContext const & Context , IBlueprintNodeBinder : : FBindingSet const & /*Bindings*/ , FBlueprintActionUiSpec * UiSpecOut , TWeakObjectPtr < UScriptStruct > StructPtr )
{
for ( UEdGraphPin * Pin : Context . Pins )
{
UScriptStruct * PinStruct = Cast < UScriptStruct > ( Pin - > PinType . PinSubCategoryObject . Get ( ) ) ;
if ( ( PinStruct ! = nullptr ) & & ( StructPtr . Get ( ) = = PinStruct ) & & ( Pin - > Direction = = EGPD_Input ) )
{
UiSpecOut - > Category = LOCTEXT ( " EmptyCategory " , " | " ) ;
break ;
}
}
} ;
2014-07-14 12:39:28 -04:00
for ( TObjectIterator < UScriptStruct > StructIt ; StructIt ; + + StructIt )
{
UScriptStruct const * Struct = ( * StructIt ) ;
2015-04-16 14:02:15 -04:00
if ( ! CanBeMade ( Struct , false ) )
2014-07-14 12:39:28 -04:00
{
continue ;
}
2014-09-17 14:57:06 -04:00
// to keep from needlessly instantiating a UBlueprintNodeSpawners, first
2014-09-10 17:09:26 -04:00
// check to make sure that the registrar is looking for actions of this type
// (could be regenerating actions for a specific asset, and therefore the
// registrar would only accept actions corresponding to that asset)
if ( ! ActionRegistrar . IsOpenForRegistration ( Struct ) )
2014-07-14 12:39:28 -04:00
{
2014-09-10 17:09:26 -04:00
continue ;
}
2014-07-14 12:39:28 -04:00
2014-09-17 14:57:06 -04:00
UBlueprintFieldNodeSpawner * NodeSpawner = UBlueprintFieldNodeSpawner : : Create ( GetClass ( ) , Struct ) ;
2014-07-14 12:39:28 -04:00
check ( NodeSpawner ! = nullptr ) ;
2014-09-17 14:57:06 -04:00
TWeakObjectPtr < UScriptStruct > NonConstStructPtr = Struct ;
NodeSpawner - > SetNodeFieldDelegate = UBlueprintFieldNodeSpawner : : FSetNodeFieldDelegate : : CreateStatic ( SetNodeStructLambda , NonConstStructPtr ) ;
2014-09-29 14:36:08 -04:00
NodeSpawner - > DynamicUiSignatureGetter = UBlueprintFieldNodeSpawner : : FUiSpecOverrideDelegate : : CreateStatic ( CategoryOverrideLambda , NonConstStructPtr ) ;
2014-09-17 14:57:06 -04:00
2014-08-23 20:16:29 -04:00
// this struct could belong to a class, or is a user defined struct
// (asset), that's why we want to make sure to register it along with
// the action (so the action knows to refresh when the class/asset is).
ActionRegistrar . AddBlueprintAction ( Struct , NodeSpawner ) ;
2014-07-14 12:39:28 -04:00
}
}
FText UK2Node_MakeStruct : : GetMenuCategory ( ) const
{
return FEditorCategoryUtils : : GetCommonCategory ( FCommonEditorCategory : : Struct ) ;
}
2014-03-14 14:13:41 -04:00
# undef LOCTEXT_NAMESPACE