2014-03-14 14:13:41 -04:00
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
# include "BlueprintGraphPrivatePCH.h"
# include "KismetCompiler.h"
# include "VariableSetHandler.h"
2014-09-12 12:56:24 -04:00
# define LOCTEXT_NAMESPACE "K2Node_VariableSet"
namespace K2Node_VariableSetImpl
{
/**
* Shared utility method for retrieving a UK2Node_VariableSet ' s bare tooltip .
*
* @ param VarName The name of the variable that the node represents .
* @ return A formatted text string , describing what the VariableSet node does .
*/
static FText GetBaseTooltip ( FName VarName ) ;
/**
* Returns true if the specified variable RepNotify AND is defined in a
* blueprint . Most ( all ? ) native rep notifies are intended to be client
* only . We are moving away from this paradigm in blueprints . So for now
* this is somewhat of a hold over to avoid nasty bugs where a K2 set node
* is calling a native function that the designer has no idea what it is
* doing .
*
* @ param VariableProperty The variable property you wish to check .
* @ return True if the specified variable RepNotify AND is defined in a blueprint .
*/
2014-09-17 13:01:38 -04:00
static bool PropertyHasLocalRepNotify ( UProperty const * VariableProperty ) ;
2014-09-12 12:56:24 -04:00
}
static FText K2Node_VariableSetImpl : : GetBaseTooltip ( FName VarName )
{
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " VarName " ) , FText : : FromName ( VarName ) ) ;
return FText : : Format ( LOCTEXT ( " SetVariableTooltip " , " Set the value of variable {VarName} " ) , Args ) ;
}
2014-09-17 13:01:38 -04:00
static bool K2Node_VariableSetImpl : : PropertyHasLocalRepNotify ( UProperty const * VariableProperty )
2014-09-12 12:56:24 -04:00
{
if ( VariableProperty ! = nullptr )
{
// We check that the variable is 'defined in a blueprint' so as to avoid
// natively defined RepNotifies being called unintentionally. Most(all?)
// native rep notifies are intended to be client only. We are moving
// away from this paradigm in blueprints. So for now this is somewhat of
// a hold over to avoid nasty bugs where a K2 set node is calling a
// native function that the designer has no idea what it is doing.
UBlueprintGeneratedClass * VariableSourceClass = Cast < UBlueprintGeneratedClass > ( VariableProperty - > GetOwnerClass ( ) ) ;
bool const bIsBlueprintProperty = ( VariableSourceClass ! = nullptr ) ;
if ( bIsBlueprintProperty & & ( VariableProperty - > RepNotifyFunc ! = NAME_None ) )
{
// Find function (ok if its defined in native class)
UFunction * Function = VariableSourceClass - > FindFunctionByName ( VariableProperty - > RepNotifyFunc ) ;
// If valid repnotify func
if ( ( Function ! = nullptr ) & & ( Function - > NumParms = = 0 ) & & ( Function - > GetReturnProperty ( ) = = nullptr ) )
{
return true ;
}
}
}
return false ;
}
2014-03-14 14:13:41 -04:00
UK2Node_VariableSet : : UK2Node_VariableSet ( const class FPostConstructInitializeProperties & PCIP )
: Super ( PCIP )
{
}
void UK2Node_VariableSet : : AllocateDefaultPins ( )
{
const UEdGraphSchema_K2 * K2Schema = GetDefault < UEdGraphSchema_K2 > ( ) ;
CreatePin ( EGPD_Input , K2Schema - > PC_Exec , TEXT ( " " ) , NULL , false , false , K2Schema - > PN_Execute ) ;
CreatePin ( EGPD_Output , K2Schema - > PC_Exec , TEXT ( " " ) , NULL , false , false , K2Schema - > PN_Then ) ;
if ( GetVarName ( ) ! = NAME_None )
{
if ( CreatePinForVariable ( EGPD_Input ) )
{
CreatePinForSelf ( ) ;
}
}
Super : : AllocateDefaultPins ( ) ;
}
void UK2Node_VariableSet : : ReallocatePinsDuringReconstruction ( TArray < UEdGraphPin * > & OldPins )
{
const UEdGraphSchema_K2 * K2Schema = GetDefault < UEdGraphSchema_K2 > ( ) ;
CreatePin ( EGPD_Input , K2Schema - > PC_Exec , TEXT ( " " ) , NULL , false , false , K2Schema - > PN_Execute ) ;
CreatePin ( EGPD_Output , K2Schema - > PC_Exec , TEXT ( " " ) , NULL , false , false , K2Schema - > PN_Then ) ;
if ( GetVarName ( ) ! = NAME_None )
{
if ( ! CreatePinForVariable ( EGPD_Input ) )
{
if ( ! RecreatePinForVariable ( EGPD_Input , OldPins ) )
{
return ;
}
}
CreatePinForSelf ( ) ;
}
}
2014-09-12 12:56:24 -04:00
2014-09-17 13:01:38 -04:00
FText UK2Node_VariableSet : : GetPropertyTooltip ( UProperty const * VariableProperty )
2014-09-12 12:56:24 -04:00
{
FText TextFormat ;
FFormatNamedArguments Args ;
bool const bHasLocalRepNotify = K2Node_VariableSetImpl : : PropertyHasLocalRepNotify ( VariableProperty ) ;
if ( bHasLocalRepNotify )
{
Args . Add ( TEXT ( " ReplicationNotifyName " ) , FText : : FromName ( VariableProperty - > RepNotifyFunc ) ) ;
TextFormat = LOCTEXT ( " SetVariableWithRepNotify_Tooltip " , " Set the value of variable {VarName} and call {ReplicationNotifyName} " ) ;
}
FName VarName = NAME_None ;
if ( VariableProperty ! = nullptr )
{
VarName = VariableProperty - > GetFName ( ) ;
UClass * SourceClass = VariableProperty - > GetOwnerClass ( ) ;
// discover if the variable property is a non blueprint user variable
bool const bIsNativeVariable = ( SourceClass ! = nullptr ) & & ( SourceClass - > ClassGeneratedBy = = nullptr ) ;
FName const TooltipMetaKey ( TEXT ( " tooltip " ) ) ;
FText SubTooltip ;
if ( bIsNativeVariable )
{
FText const PropertyTooltip = VariableProperty - > GetToolTipText ( ) ;
if ( ! PropertyTooltip . IsEmpty ( ) )
{
// See if the native property has a tooltip
SubTooltip = PropertyTooltip ;
FString TooltipName = FString : : Printf ( TEXT ( " %s.%s " ) , * VarName . ToString ( ) , * TooltipMetaKey . ToString ( ) ) ;
FText : : FindText ( * VariableProperty - > GetFullGroupName ( true ) , * TooltipName , SubTooltip ) ;
}
}
else if ( UBlueprint * VarBlueprint = Cast < UBlueprint > ( SourceClass - > ClassGeneratedBy ) )
{
FString UserTooltipData ;
if ( FBlueprintEditorUtils : : GetBlueprintVariableMetaData ( VarBlueprint , VarName , /*InLocalVarScope =*/ nullptr , TooltipMetaKey , UserTooltipData ) )
{
SubTooltip = FText : : FromString ( UserTooltipData ) ;
}
}
if ( ! SubTooltip . IsEmpty ( ) )
{
Args . Add ( TEXT ( " PropertyTooltip " ) , SubTooltip ) ;
if ( bHasLocalRepNotify )
{
TextFormat = LOCTEXT ( " SetVariablePropertyWithRepNotify_Tooltip " , " Set the value of variable {VarName} and call {ReplicationNotifyName} \n {PropertyTooltip} " ) ;
}
else
{
TextFormat = LOCTEXT ( " SetVariableProperty_Tooltip " , " Set the value of variable {VarName} \n {PropertyTooltip} " ) ;
}
}
}
if ( TextFormat . IsEmpty ( ) )
{
return K2Node_VariableSetImpl : : GetBaseTooltip ( VarName ) ;
}
else
{
Args . Add ( TEXT ( " VarName " ) , FText : : FromName ( VarName ) ) ;
return FText : : Format ( TextFormat , Args ) ;
}
}
FText UK2Node_VariableSet : : GetBlueprintVarTooltip ( FBPVariableDescription const & VarDesc )
{
FName const TooltipMetaKey ( TEXT ( " tooltip " ) ) ;
int32 const MetaIndex = VarDesc . FindMetaDataEntryIndexForKey ( TooltipMetaKey ) ;
bool const bHasTooltipData = ( MetaIndex ! = INDEX_NONE ) ;
if ( bHasTooltipData )
{
FString UserTooltipData = VarDesc . GetMetaData ( TooltipMetaKey ) ;
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " VarName " ) , FText : : FromName ( VarDesc . VarName ) ) ;
Args . Add ( TEXT ( " UserTooltip " ) , FText : : FromString ( UserTooltipData ) ) ;
return FText : : Format ( LOCTEXT ( " SetVariableProperty_Tooltip " , " Set the value of variable {VarName} \n {UserTooltip} " ) , Args ) ;
}
return K2Node_VariableSetImpl : : GetBaseTooltip ( VarDesc . VarName ) ;
}
2014-09-03 18:14:09 -04:00
FText UK2Node_VariableSet : : GetTooltipText ( ) const
2014-03-14 14:13:41 -04:00
{
2014-09-24 14:15:13 -04:00
// @TODO: The variable name mutates as the user makes changes to the
// underlying property, so until we can catch all those cases, we're
// going to leave this optimization off
//if (CachedTooltip.IsOutOfDate())
2014-09-03 18:17:44 -04:00
{
2014-09-12 12:56:24 -04:00
if ( UProperty * Property = GetPropertyForVariable ( ) )
{
CachedTooltip = GetPropertyTooltip ( Property ) ;
}
else if ( FBPVariableDescription const * VarDesc = GetBlueprintVarDescription ( ) )
{
CachedTooltip = GetBlueprintVarTooltip ( * VarDesc ) ;
}
else
{
CachedTooltip = K2Node_VariableSetImpl : : GetBaseTooltip ( GetVarName ( ) ) ;
}
2014-09-03 18:17:44 -04:00
}
2014-09-12 12:56:24 -04:00
return CachedTooltip ;
2014-09-03 18:17:44 -04:00
2014-03-14 14:13:41 -04:00
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " VarName " ) , FText : : FromString ( GetVarNameString ( ) ) ) ;
Args . Add ( TEXT ( " ReplicationCall " ) , FText : : GetEmpty ( ) ) ;
Args . Add ( TEXT ( " ReplicationNotifyName " ) , FText : : GetEmpty ( ) ) ;
Args . Add ( TEXT ( " TextPartition " ) , FText : : GetEmpty ( ) ) ;
Args . Add ( TEXT ( " MetaData " ) , FText : : GetEmpty ( ) ) ;
if ( HasLocalRepNotify ( ) )
{
Args . Add ( TEXT ( " ReplicationCall " ) , NSLOCTEXT ( " K2Node " , " VariableSet_ReplicationCall " , " and call " ) ) ;
Args . Add ( TEXT ( " ReplicationNotifyName " ) , FText : : FromString ( GetRepNotifyName ( ) . ToString ( ) ) ) ;
}
if ( UProperty * Property = GetPropertyForVariable ( ) )
{
// discover if the variable property is a non blueprint user variable
UClass * SourceClass = Property - > GetOwnerClass ( ) ;
if ( SourceClass & & SourceClass - > ClassGeneratedBy = = NULL )
{
const FString MetaData = Property - > GetToolTipText ( ) . ToString ( ) ;
if ( ! MetaData . IsEmpty ( ) )
{
// See if the property associated with this editor has a tooltip
FText PropertyMetaData = FText : : FromString ( * MetaData ) ;
FString TooltipName = FString : : Printf ( TEXT ( " %s.tooltip " ) , * ( Property - > GetName ( ) ) ) ;
FText : : FindText ( * ( Property - > GetFullGroupName ( true ) ) , * TooltipName , PropertyMetaData ) ;
Args . Add ( TEXT ( " TextPartition " ) , FText : : FromString ( " \n " ) ) ;
Args . Add ( TEXT ( " MetaData " ) , PropertyMetaData ) ;
}
}
}
2014-09-03 18:17:44 -04:00
// FText::Format() is slow, so we cache this to save on performance
CachedTooltip = FText : : Format ( NSLOCTEXT ( " K2Node " , " SetValueOfVariable " , " Set the value of variable {VarName}{ReplicationCall}{ReplicationNotifyName}{TextPartition}{MetaData} " ) , Args ) ;
return CachedTooltip ;
2014-03-14 14:13:41 -04:00
}
2014-04-23 18:30:37 -04:00
FText UK2Node_VariableSet : : GetNodeTitle ( ENodeTitleType : : Type TitleType ) const
2014-03-14 14:13:41 -04:00
{
const UEdGraphSchema_K2 * K2Schema = GetDefault < UEdGraphSchema_K2 > ( ) ;
2014-04-23 18:30:37 -04:00
// If there is only one variable being written (one non-meta input pin), the title can be made the variable name
FString InputPinName ;
int32 NumInputsFound = 0 ;
for ( int32 PinIndex = 0 ; PinIndex < Pins . Num ( ) ; + + PinIndex )
{
UEdGraphPin * Pin = Pins [ PinIndex ] ;
if ( ( Pin - > Direction = = EGPD_Input ) & & ( ! K2Schema - > IsMetaPin ( * Pin ) ) )
{
+ + NumInputsFound ;
InputPinName = Pin - > PinName ;
}
}
2014-09-02 19:08:09 -04:00
if ( NumInputsFound ! = 1 )
{
return HasLocalRepNotify ( ) ? NSLOCTEXT ( " K2Node " , " SetWithNotify " , " Set with Notify " ) : NSLOCTEXT ( " K2Node " , " Set " , " Set " ) ;
}
2014-09-24 14:15:13 -04:00
// @TODO: The variable name mutates as the user makes changes to the
// underlying property, so until we can catch all those cases, we're
// going to leave this optimization off
else //if (CachedNodeTitle.IsOutOfDate())
2014-04-23 18:30:37 -04:00
{
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " PinName " ) , FText : : FromString ( InputPinName ) ) ;
2014-09-02 19:08:09 -04:00
// FText::Format() is slow, so we cache this to save on performance
if ( HasLocalRepNotify ( ) )
2014-04-23 18:30:37 -04:00
{
2014-09-02 19:08:09 -04:00
CachedNodeTitle = FText : : Format ( NSLOCTEXT ( " K2Node " , " SetWithNotifyPinName " , " Set with Notify {PinName} " ) , Args ) ;
2014-04-23 18:30:37 -04:00
}
else
{
2014-09-02 19:08:09 -04:00
CachedNodeTitle = FText : : Format ( NSLOCTEXT ( " K2Node " , " SetPinName " , " Set {PinName} " ) , Args ) ;
2014-04-23 18:30:37 -04:00
}
}
2014-09-02 19:08:09 -04:00
return CachedNodeTitle ;
2014-04-23 18:30:37 -04:00
}
2014-03-14 14:13:41 -04:00
/** Returns true if the variable we are setting has a RepNotify AND was defined in a blueprint
* The ' defined in a blueprint ' is to avoid natively defined RepNotifies being called unintentionally .
* Most ( all ? ) native rep notifies are intended to be client only . We are moving away from this paradigm in blueprints
* So for now this is somewhat of a hold over to avoid nasty bugs where a K2 set node is calling a native function that the
* designer has no idea what it is doing .
*/
bool UK2Node_VariableSet : : HasLocalRepNotify ( ) const
{
2014-09-12 12:56:24 -04:00
return K2Node_VariableSetImpl : : PropertyHasLocalRepNotify ( GetPropertyForVariable ( ) ) ;
2014-03-14 14:13:41 -04:00
}
bool UK2Node_VariableSet : : ShouldFlushDormancyOnSet ( ) const
{
if ( ! GetVariableSourceClass ( ) - > IsChildOf ( AActor : : StaticClass ( ) ) )
{
return false ;
}
// Flush net dormancy before setting a replicated property
UProperty * Property = FindField < UProperty > ( GetVariableSourceClass ( ) , GetVarName ( ) ) ;
return ( Property ! = NULL & & ( Property - > PropertyFlags & CPF_Net ) ) ;
}
FName UK2Node_VariableSet : : GetRepNotifyName ( ) const
{
UProperty * Property = GetPropertyForVariable ( ) ;
if ( Property )
{
return Property - > RepNotifyFunc ;
}
return NAME_None ;
}
FNodeHandlingFunctor * UK2Node_VariableSet : : CreateNodeHandler ( FKismetCompilerContext & CompilerContext ) const
{
return new FKCHandler_VariableSet ( CompilerContext ) ;
}
2014-09-12 12:56:24 -04:00
# undef LOCTEXT_NAMESPACE