2014-03-14 14:13:41 -04:00
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
# include "BlueprintGraphPrivatePCH.h"
# include "KismetCompiler.h"
2014-07-14 12:39:28 -04:00
# include "BlueprintNodeSpawner.h"
# include "EditorCategoryUtils.h"
2014-03-14 14:13:41 -04:00
# define LOCTEXT_NAMESPACE "K2Node_BreakStruct"
//////////////////////////////////////////////////////////////////////////
// FKCHandler_BreakStruct
class FKCHandler_BreakStruct : public FNodeHandlingFunctor
{
public :
FKCHandler_BreakStruct ( FKismetCompilerContext & InCompilerContext )
: FNodeHandlingFunctor ( InCompilerContext )
{
}
FBPTerminal * RegisterInputTerm ( FKismetFunctionContext & Context , UK2Node_BreakStruct * Node )
{
check ( NULL ! = Node ) ;
if ( NULL = = Node - > StructType )
{
CompilerContext . MessageLog . Error ( * LOCTEXT ( " BreakStruct_UnknownStructure_Error " , " Unknown structure to break for @@ " ) . ToString ( ) , Node ) ;
return NULL ;
}
//Find input pin
UEdGraphPin * InputPin = NULL ;
for ( int32 PinIndex = 0 ; PinIndex < Node - > Pins . Num ( ) ; + + PinIndex )
{
UEdGraphPin * Pin = Node - > Pins [ PinIndex ] ;
if ( Pin & & ( EGPD_Input = = Pin - > Direction ) )
{
InputPin = Pin ;
break ;
}
}
check ( NULL ! = InputPin ) ;
//Find structure source net
UEdGraphPin * Net = FEdGraphUtilities : : GetNetFromPin ( InputPin ) ;
check ( NULL ! = Net ) ;
FBPTerminal * * FoundTerm = Context . NetMap . Find ( Net ) ;
FBPTerminal * Term = FoundTerm ? * FoundTerm : NULL ;
if ( NULL = = Term )
{
// Dont allow literal
if ( ( Net - > Direction = = EGPD_Input ) & & ( Net - > LinkedTo . Num ( ) = = 0 ) )
{
CompilerContext . MessageLog . Error ( * LOCTEXT ( " InvalidNoInputStructure_Error " , " No input structure to break for @@ " ) . ToString ( ) , Net ) ;
return NULL ;
}
// standard register net
else
{
Term = new ( Context . IsEventGraph ( ) ? Context . EventGraphLocals : Context . Locals ) FBPTerminal ( ) ;
Term - > CopyFromPin ( Net , Context . NetNameMap - > MakeValidName ( Net ) ) ;
}
Context . NetMap . Add ( Net , Term ) ;
}
UStruct * StructInTerm = Cast < UStruct > ( Term - > Type . PinSubCategoryObject . Get ( ) ) ;
if ( NULL = = StructInTerm | | ! StructInTerm - > IsChildOf ( Node - > StructType ) )
{
CompilerContext . MessageLog . Error ( * LOCTEXT ( " BreakStruct_NoMatch_Error " , " Structures don't match for @@ " ) . ToString ( ) , Node ) ;
}
return Term ;
}
void RegisterOutputTerm ( FKismetFunctionContext & Context , UScriptStruct * StructType , UEdGraphPin * Net , FBPTerminal * ContextTerm )
{
UProperty * BoundProperty = FindField < UProperty > ( StructType , * ( Net - > PinName ) ) ;
if ( BoundProperty ! = NULL )
{
FBPTerminal * Term = new ( Context . IsEventGraph ( ) ? Context . EventGraphLocals : Context . Locals ) FBPTerminal ( ) ;
Term - > CopyFromPin ( Net , Net - > PinName ) ;
Term - > AssociatedVarProperty = BoundProperty ;
Context . NetMap . Add ( Net , Term ) ;
Term - > Context = ContextTerm ;
if ( BoundProperty - > HasAnyPropertyFlags ( CPF_BlueprintReadOnly ) )
{
Term - > bIsConst = true ;
}
}
else
{
CompilerContext . MessageLog . Error ( TEXT ( " Failed to find a struct member for @@ " ) , Net ) ;
}
}
2014-06-13 06:14:46 -04:00
virtual void RegisterNets ( FKismetFunctionContext & Context , UEdGraphNode * InNode ) override
2014-03-14 14:13:41 -04:00
{
UK2Node_BreakStruct * Node = Cast < UK2Node_BreakStruct > ( InNode ) ;
check ( NULL ! = Node ) ;
if ( ! UK2Node_BreakStruct : : CanBeBroken ( Node - > StructType ) )
{
CompilerContext . MessageLog . Warning ( * LOCTEXT ( " BreakStruct_NoBreak_Error " , " The structure cannot be broken using generic 'break' node @@. Try use specialized 'break' function if available. " ) . ToString ( ) , Node ) ;
}
if ( FBPTerminal * StructContextTerm = RegisterInputTerm ( Context , Node ) )
{
for ( int32 PinIndex = 0 ; PinIndex < Node - > Pins . Num ( ) ; + + PinIndex )
{
UEdGraphPin * Pin = Node - > Pins [ PinIndex ] ;
if ( NULL ! = Pin & & EGPD_Output = = Pin - > Direction )
{
RegisterOutputTerm ( Context , Node - > StructType , Pin , StructContextTerm ) ;
}
}
}
}
} ;
UK2Node_BreakStruct : : UK2Node_BreakStruct ( const class FPostConstructInitializeProperties & PCIP ) : Super ( PCIP )
{
}
2014-08-05 14:16:02 -04:00
bool UK2Node_BreakStruct : : CanCreatePinForProperty ( const UProperty * Property )
{
const UEdGraphSchema_K2 * Schema = GetDefault < UEdGraphSchema_K2 > ( ) ;
FEdGraphPinType DumbGraphPinType ;
const bool bConvertable = Schema - > ConvertPropertyToPinType ( Property , /*out*/ DumbGraphPinType ) ;
//TODO: remove CPF_Edit in a next release.
const bool bVisible = Property ? Property - > HasAnyPropertyFlags ( CPF_Edit | CPF_BlueprintVisible ) : false ;
return bVisible & & bConvertable ;
}
2014-03-14 14:13:41 -04:00
bool UK2Node_BreakStruct : : CanBeBroken ( const UScriptStruct * Struct )
{
const UEdGraphSchema_K2 * Schema = GetDefault < UEdGraphSchema_K2 > ( ) ;
2014-06-16 10:30:41 -04:00
if ( Struct & & Schema & & ! Struct - > HasMetaData ( TEXT ( " HasNativeBreak " ) ) )
2014-03-14 14:13:41 -04:00
{
for ( TFieldIterator < UProperty > It ( Struct ) ; It ; + + It )
{
2014-08-05 14:16:02 -04:00
if ( CanCreatePinForProperty ( * It ) )
2014-03-14 14:13:41 -04:00
{
2014-08-05 14:16:02 -04:00
return true ;
2014-03-14 14:13:41 -04:00
}
}
}
return false ;
}
void UK2Node_BreakStruct : : AllocateDefaultPins ( )
{
const UEdGraphSchema_K2 * Schema = GetDefault < UEdGraphSchema_K2 > ( ) ;
if ( Schema & & StructType )
{
2014-04-24 15:44:17 -04:00
CreatePin ( EGPD_Input , Schema - > PC_Struct , TEXT ( " " ) , StructType , false , true , StructType - > GetName ( ) , true ) ;
2014-03-14 14:13:41 -04:00
2014-08-05 14:16:02 -04:00
struct FBreakStructPinManager : public FStructOperationOptionalPinManager
{
virtual bool CanTreatPropertyAsOptional ( UProperty * TestProperty ) const override
{
return UK2Node_BreakStruct : : CanCreatePinForProperty ( TestProperty ) ;
}
} ;
{
FBreakStructPinManager OptionalPinManager ;
OptionalPinManager . RebuildPropertyList ( ShowPinForProperties , StructType ) ;
OptionalPinManager . CreateVisiblePins ( ShowPinForProperties , StructType , EGPD_Output , this ) ;
}
2014-03-14 14:13:41 -04:00
// 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 ;
}
}
}
}
}
2014-04-23 18:30:37 -04:00
FText UK2Node_BreakStruct : : GetNodeTitle ( ENodeTitleType : : Type TitleType ) const
2014-03-14 14:13:41 -04:00
{
2014-04-23 18:30:37 -04:00
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " StructName " ) , FText : : FromString ( StructType ? StructType - > GetName ( ) : FString ( ) ) ) ;
return FText : : Format ( LOCTEXT ( " BreakNodeTitle " , " Break {StructName} " ) , Args ) ;
}
2014-03-14 14:13:41 -04:00
FString UK2Node_BreakStruct : : GetTooltip ( ) const
{
return FString : : Printf (
* LOCTEXT ( " MakeStruct_Tooltip " , " Adds a node that breaks a '%s' into its member fields " ) . ToString ( ) ,
* ( StructType ? StructType - > GetName ( ) : FString ( ) )
) ;
}
void UK2Node_BreakStruct : : 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 ( CanCreatePinForProperty ( 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 ;
const UEdGraphPin * Pin = Property ? FindPin ( Property - > GetName ( ) ) : NULL ;
const bool bIsLinked = Pin & & Pin - > LinkedTo . Num ( ) ;
if ( ! bIsBlueprintVisible & & bIsLinked )
{
MessageLog . Warning ( * LOCTEXT ( " PropertyIsNotBPVisible_Warning " , " @@ - the native property is not tagged as BlueprintReadWrite or BlueprintReadOnly, the pin will be removed in a future release. " ) . ToString ( ) , Pin ) ;
}
if ( ( Property - > ArrayDim > 1 ) & & bIsLinked )
{
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 or BlueprintReadOnly. The node will be removed in a future release. " ) . ToString ( ) , this ) ;
}
}
2014-03-14 14:13:41 -04:00
}
FLinearColor UK2Node_BreakStruct : : 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 ( ) ;
}
UK2Node : : ERedirectType UK2Node_BreakStruct : : DoPinsMatchForReconstruction ( const UEdGraphPin * NewPin , int32 NewPinIndex , const UEdGraphPin * OldPin , int32 OldPinIndex ) const
{
ERedirectType Result = UK2Node : : DoPinsMatchForReconstruction ( NewPin , NewPinIndex , OldPin , OldPinIndex ) ;
2014-06-16 10:30:41 -04:00
if ( ( ERedirectType_None = = Result ) & & NewPin & & OldPin )
2014-03-14 14:13:41 -04:00
{
2014-06-16 10:30:41 -04:00
if ( ( EGPD_Input = = NewPin - > Direction ) & & ( EGPD_Input = = OldPin - > Direction ) )
{
const UEdGraphSchema_K2 * K2Schema = GetDefault < UEdGraphSchema_K2 > ( ) ;
if ( K2Schema - > ArePinTypesCompatible ( NewPin - > PinType , OldPin - > PinType ) )
{
Result = ERedirectType_Custom ;
}
}
else if ( ( EGPD_Output = = NewPin - > Direction ) & & ( EGPD_Output = = 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 ;
}
FNodeHandlingFunctor * UK2Node_BreakStruct : : CreateNodeHandler ( class FKismetCompilerContext & CompilerContext ) const
{
return new FKCHandler_BreakStruct ( CompilerContext ) ;
}
2014-07-14 12:39:28 -04:00
void UK2Node_BreakStruct : : GetMenuActions ( TArray < UBlueprintNodeSpawner * > & ActionListOut ) const
{
for ( TObjectIterator < UScriptStruct > StructIt ; StructIt ; + + StructIt )
{
UScriptStruct const * Struct = ( * StructIt ) ;
// we only want to add autonomous structs here; those belonging to a
// certain class should instead be associated with that class (so when
// the class is modified we can easily handle any structs that were changed).
bool bIsStandaloneStruct = Struct - > GetOuter ( ) - > IsA ( UPackage : : StaticClass ( ) ) ;
if ( ! bIsStandaloneStruct | | ! UEdGraphSchema_K2 : : IsAllowableBlueprintVariableType ( Struct ) | | ! CanBeBroken ( Struct ) )
{
continue ;
}
auto CustomizeBreakNodeLambda = [ ] ( UEdGraphNode * NewNode , bool bIsTemplateNode , TWeakObjectPtr < UScriptStruct > StructPtr )
{
UK2Node_BreakStruct * BreakNode = CastChecked < UK2Node_BreakStruct > ( NewNode ) ;
if ( StructPtr . IsValid ( ) )
{
BreakNode - > StructType = StructPtr . Get ( ) ;
}
} ;
UBlueprintNodeSpawner * NodeSpawner = UBlueprintNodeSpawner : : Create ( GetClass ( ) ) ;
check ( NodeSpawner ! = nullptr ) ;
ActionListOut . Add ( NodeSpawner ) ;
TWeakObjectPtr < UScriptStruct > StructPtr = Struct ;
NodeSpawner - > CustomizeNodeDelegate = UBlueprintNodeSpawner : : FCustomizeNodeDelegate : : CreateStatic ( CustomizeBreakNodeLambda , StructPtr ) ;
}
}
FText UK2Node_BreakStruct : : GetMenuCategory ( ) const
{
return FEditorCategoryUtils : : GetCommonCategory ( FCommonEditorCategory : : Struct ) ;
}
2014-03-14 14:13:41 -04:00
# undef LOCTEXT_NAMESPACE