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"
# 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-10-14 10:29:11 -04:00
UK2Node_VariableSet : : UK2Node_VariableSet ( const FObjectInitializer & ObjectInitializer )
: Super ( ObjectInitializer )
2014-03-14 14:13:41 -04:00
{
}
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 ( ) ;
}
2014-11-20 10:21:19 -05:00
if ( CreatePinForVariable ( EGPD_Output , GetVariableOutputPinName ( ) ) )
{
CreateOutputPinTooltip ( ) ;
}
2014-03-14 14:13:41 -04:00
}
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 ;
}
}
2014-11-20 10:21:19 -05:00
if ( ! CreatePinForVariable ( EGPD_Output , GetVariableOutputPinName ( ) ) )
{
if ( ! RecreatePinForVariable ( EGPD_Output , OldPins , GetVariableOutputPinName ( ) ) )
{
return ;
}
}
CreateOutputPinTooltip ( ) ;
2014-03-14 14:13:41 -04:00
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 ) ;
FName VarName = NAME_None ;
if ( VariableProperty ! = nullptr )
{
2015-03-31 20:12:31 -04:00
if ( bHasLocalRepNotify )
{
Args . Add ( TEXT ( " ReplicationNotifyName " ) , FText : : FromName ( VariableProperty - > RepNotifyFunc ) ) ;
TextFormat = LOCTEXT ( " SetVariableWithRepNotify_Tooltip " , " Set the value of variable {VarName} and call {ReplicationNotifyName} " ) ;
}
2014-09-12 12:56:24 -04:00
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
{
2015-04-02 11:16:23 -04:00
if ( CachedTooltip . IsOutOfDate ( this ) )
2014-09-03 18:17:44 -04:00
{
2014-09-12 12:56:24 -04:00
if ( UProperty * Property = GetPropertyForVariable ( ) )
{
2015-04-02 11:16:23 -04:00
CachedTooltip . SetCachedText ( GetPropertyTooltip ( Property ) , this ) ;
2014-09-12 12:56:24 -04:00
}
else if ( FBPVariableDescription const * VarDesc = GetBlueprintVarDescription ( ) )
{
2015-04-02 11:16:23 -04:00
CachedTooltip . SetCachedText ( GetBlueprintVarTooltip ( * VarDesc ) , this ) ;
2014-09-12 12:56:24 -04:00
}
else
{
2015-04-02 11:16:23 -04:00
CachedTooltip . SetCachedText ( K2Node_VariableSetImpl : : GetBaseTooltip ( GetVarName ( ) ) , this ) ;
2014-09-12 12:56:24 -04:00
}
2014-09-03 18:17:44 -04:00
}
2014-09-12 12:56:24 -04:00
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
2015-04-02 11:16:23 -04:00
else if ( CachedNodeTitle . IsOutOfDate ( this ) )
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
{
2015-04-02 11:16:23 -04:00
CachedNodeTitle . SetCachedText ( FText : : Format ( NSLOCTEXT ( " K2Node " , " SetWithNotifyPinName " , " Set with Notify {PinName} " ) , Args ) , this ) ;
2014-04-23 18:30:37 -04:00
}
else
{
2015-04-02 11:16:23 -04:00
CachedNodeTitle . SetCachedText ( FText : : Format ( NSLOCTEXT ( " K2Node " , " SetPinName " , " Set {PinName} " ) , Args ) , this ) ;
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
2014-11-20 10:21:19 -05:00
FString UK2Node_VariableSet : : GetVariableOutputPinName ( ) const
{
2014-12-01 10:33:00 -05:00
return TEXT ( " Output_Get " ) ;
2014-11-20 10:21:19 -05:00
}
void UK2Node_VariableSet : : CreateOutputPinTooltip ( )
{
UEdGraphPin * Pin = FindPin ( GetVariableOutputPinName ( ) ) ;
check ( Pin ) ;
Pin - > PinToolTip = NSLOCTEXT ( " K2Node " , " SetPinOutputTooltip " , " Retrieves the value of the variable, can use instead of a separate Get node " ) . ToString ( ) ;
}
2015-01-07 09:52:40 -05:00
FText UK2Node_VariableSet : : GetPinNameOverride ( const UEdGraphPin & Pin ) const
2014-11-20 10:21:19 -05:00
{
// Stop the output pin for the variable, effectively the "get" pin, from displaying a name.
const UEdGraphSchema_K2 * K2Schema = GetDefault < UEdGraphSchema_K2 > ( ) ;
if ( Pin . Direction = = EGPD_Output | | Pin . PinType . PinCategory = = K2Schema - > PC_Exec )
{
2015-01-07 09:52:40 -05:00
return FText : : GetEmpty ( ) ;
2014-11-20 10:21:19 -05:00
}
2015-01-07 09:52:40 -05:00
return ! Pin . PinFriendlyName . IsEmpty ( ) ? Pin . PinFriendlyName : FText : : FromString ( Pin . PinName ) ;
2014-11-20 10:21:19 -05:00
}
void UK2Node_VariableSet : : ExpandNode ( class FKismetCompilerContext & CompilerContext , UEdGraph * SourceGraph )
{
Super : : ExpandNode ( CompilerContext , SourceGraph ) ;
if ( CompilerContext . bIsFullCompile )
{
const UEdGraphSchema_K2 * K2Schema = CompilerContext . GetSchema ( ) ;
UEdGraphPin * Pin = FindPin ( GetVariableOutputPinName ( ) ) ;
if ( Pin )
{
// If the output pin is linked, we need to spawn a separate "Get" node and hook it up.
if ( Pin - > LinkedTo . Num ( ) )
{
UProperty * VariableProperty = GetPropertyForVariable ( ) ;
if ( VariableProperty )
{
UK2Node_VariableGet * VariableGetNode = CompilerContext . SpawnIntermediateNode < UK2Node_VariableGet > ( this , SourceGraph ) ;
VariableGetNode - > VariableReference = VariableReference ;
VariableGetNode - > AllocateDefaultPins ( ) ;
CompilerContext . MessageLog . NotifyIntermediateObjectCreation ( VariableGetNode , this ) ;
CompilerContext . MovePinLinksToIntermediate ( * Pin , * VariableGetNode - > FindPin ( GetVarNameString ( ) ) ) ;
// Duplicate the connection to the self pin.
UEdGraphPin * SetSelfPin = K2Schema - > FindSelfPin ( * this , EGPD_Input ) ;
UEdGraphPin * GetSelfPin = K2Schema - > FindSelfPin ( * VariableGetNode , EGPD_Input ) ;
if ( SetSelfPin & & GetSelfPin )
{
CompilerContext . CopyPinLinksToIntermediate ( * SetSelfPin , * GetSelfPin ) ;
}
}
}
Pins . Remove ( Pin ) ;
}
}
}
2014-09-12 12:56:24 -04:00
# undef LOCTEXT_NAMESPACE