2014-03-14 14:13:41 -04:00
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
# include "BlueprintGraphPrivatePCH.h"
# include "CompilerResultsLog.h"
# include "KismetCompiler.h"
# define LOCTEXT_NAMESPACE "K2Node_DelegateSet"
//////////////////////////////////////////////////////////////////////////
// FKCHandler_BindToMulticastDelegate
class FKCHandler_BindToMulticastDelegate : public FNodeHandlingFunctor
{
protected :
TMap < UEdGraphNode * , FBPTerminal * > LocalDelegateMap ;
public :
FKCHandler_BindToMulticastDelegate ( FKismetCompilerContext & InCompilerContext )
: FNodeHandlingFunctor ( InCompilerContext )
{
}
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_DelegateSet * DelegateNode = Cast < UK2Node_DelegateSet > ( Node ) ;
if ( DelegateNode )
{
CompilerContext . MessageLog . Warning ( * FString ( * LOCTEXT ( " DeprecatedDelegateSet_Warning " , " DelegateSet node @@ is Deprecated. It should be replaced by an EventCaller Bind node " ) . ToString ( ) ) , DelegateNode ) ;
// Create a term to store the locally created delegate that we'll use to add to the MC delegate
2014-09-26 11:32:41 -04:00
FBPTerminal * DelegateTerm = Context . CreateLocalTerminal ( ) ;
2014-03-14 14:13:41 -04:00
DelegateTerm - > Type . PinCategory = CompilerContext . GetSchema ( ) - > PC_Delegate ;
2014-04-23 20:18:55 -04:00
FMemberReference : : FillSimpleMemberReference < UFunction > ( DelegateNode - > GetDelegateSignature ( ) , DelegateTerm - > Type . PinSubCategoryMemberReference ) ;
2014-03-14 14:13:41 -04:00
DelegateTerm - > Source = Node ;
DelegateTerm - > Name = Context . NetNameMap - > MakeValidName ( Node ) + TEXT ( " _TempBindingDelegate " ) ;
LocalDelegateMap . Add ( Node , DelegateTerm ) ;
// The only net we need to register for this node is the delegate's target (self) pin, since the others are expanded to their own event node
RegisterDelegateNet ( Context , DelegateNode ) ;
}
}
void RegisterDelegateNet ( FKismetFunctionContext & Context , UK2Node_DelegateSet * DelegateNode )
{
check ( DelegateNode ) ;
UEdGraphPin * DelegatePin = DelegateNode - > GetDelegateOwner ( ) ;
check ( DelegatePin ) ;
// Find the property on the specified scope
UProperty * BoundProperty = NULL ;
for ( TFieldIterator < UProperty > It ( DelegateNode - > DelegatePropertyClass , EFieldIteratorFlags : : IncludeSuper ) ; It ; + + It )
{
UProperty * Prop = * It ;
if ( Prop - > GetFName ( ) = = DelegateNode - > DelegatePropertyName )
{
check ( Prop - > HasAllPropertyFlags ( CPF_BlueprintAssignable ) ) ;
BoundProperty = Prop ;
break ;
}
}
// Create a term for this property
if ( BoundProperty ! = NULL )
{
FBPTerminal * Term = new ( Context . VariableReferences ) FBPTerminal ( ) ;
Term - > CopyFromPin ( DelegatePin , DelegatePin - > PinName ) ;
Term - > AssociatedVarProperty = BoundProperty ;
Context . NetMap . Add ( DelegatePin , Term ) ;
// Find the context for this term (the object owning the delegate property)
FBPTerminal * * pContextTerm = Context . NetMap . Find ( FEdGraphUtilities : : GetNetFromPin ( DelegatePin ) ) ;
if ( pContextTerm )
{
Term - > Context = * pContextTerm ;
}
else
{
CompilerContext . MessageLog . Error ( * FString ( * LOCTEXT ( " FindDynamicallyBoundDelegate_Error " , " Couldn't find target for dynamically bound delegate node @@ " ) . ToString ( ) ) , DelegateNode ) ;
}
}
}
2014-06-13 06:14:46 -04:00
virtual void Compile ( FKismetFunctionContext & Context , UEdGraphNode * Node ) override
2014-03-14 14:13:41 -04:00
{
const UK2Node_DelegateSet * DelegateNode = Cast < UK2Node_DelegateSet > ( Node ) ;
check ( DelegateNode ) ;
// Verify that the event has a darget to be bound to
UEdGraphPin * DelegateOwnerPin = DelegateNode - > GetDelegateOwner ( ) ;
if ( DelegateOwnerPin - > LinkedTo . Num ( ) = = 0 )
{
CompilerContext . MessageLog . Error ( * FString ( * LOCTEXT ( " FindDynamicallyBoundDelegate_Error " , " Couldn't find target for dynamically bound delegate node @@ " ) . ToString ( ) ) , DelegateNode ) ;
return ;
}
FBPTerminal * * pDelegateOwnerTerm = DelegateOwnerPin ? Context . NetMap . Find ( DelegateOwnerPin ) : NULL ;
// Create a delegate name term
2014-09-26 11:32:41 -04:00
FBPTerminal * DelegateNameTerm = Context . CreateLocalTerminal ( ETerminalSpecification : : TS_Literal ) ;
2014-03-14 14:13:41 -04:00
DelegateNameTerm - > Type . PinCategory = CompilerContext . GetSchema ( ) - > PC_Name ;
DelegateNameTerm - > Name = DelegateNode - > GetDelegateTargetEntryPointName ( ) . ToString ( ) ;
DelegateNameTerm - > bIsLiteral = true ;
// Create a local delegate, which we can then add to the multicast delegate
FBPTerminal * LocalDelegate = * LocalDelegateMap . Find ( Node ) ;
FBlueprintCompiledStatement & Statement = Context . AppendStatementForNode ( Node ) ;
Statement . Type = KCST_Assignment ;
Statement . LHS = LocalDelegate ;
Statement . RHS . Add ( DelegateNameTerm ) ;
// Add the local delegate to the MC delegate
FBlueprintCompiledStatement & AddStatement = Context . AppendStatementForNode ( Node ) ;
AddStatement . Type = KCST_AddMulticastDelegate ;
AddStatement . LHS = * pDelegateOwnerTerm ;
AddStatement . RHS . Add ( LocalDelegate ) ;
GenerateSimpleThenGoto ( Context , * Node , DelegateNode - > FindPin ( CompilerContext . GetSchema ( ) - > PN_Then ) ) ;
FNodeHandlingFunctor : : Compile ( Context , Node ) ;
}
} ;
UK2Node_DelegateSet : : UK2Node_DelegateSet ( const class FPostConstructInitializeProperties & PCIP )
: Super ( PCIP )
{
}
void UK2Node_DelegateSet : : AllocateDefaultPins ( )
{
const UEdGraphSchema_K2 * K2Schema = GetDefault < UEdGraphSchema_K2 > ( ) ;
// Cache off the delegate signature, which will update the DelegatePropertyName as well, if it's been redirected
UFunction * DelegateSignature = GetDelegateSignature ( ) ;
CreatePin ( EGPD_Input , K2Schema - > PC_Exec , TEXT ( " " ) , NULL , false , false , K2Schema - > PN_Execute ) ;
CreatePin ( EGPD_Input , K2Schema - > PC_Object , TEXT ( " " ) , DelegatePropertyClass , false , false , DelegatePropertyName . ToString ( ) ) ;
CreatePin ( EGPD_Output , K2Schema - > PC_Exec , TEXT ( " " ) , NULL , false , false , K2Schema - > PN_Then ) ;
CreatePin ( EGPD_Output , K2Schema - > PC_Exec , TEXT ( " " ) , NULL , false , false , K2Schema - > PN_DelegateEntry ) ;
CreatePinsForFunctionEntryExit ( DelegateSignature , true ) ;
Super : : AllocateDefaultPins ( ) ;
}
2014-09-03 18:14:09 -04:00
FText UK2Node_DelegateSet : : GetTooltipText ( ) const
2014-03-14 14:13:41 -04:00
{
2014-09-03 18:17:44 -04:00
if ( CachedTooltip . IsOutOfDate ( ) )
2014-03-14 14:13:41 -04:00
{
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 " , " CreateEventForDelegate " , " Create an event tied to the delegate {0} " ) , FText : : FromName ( DelegatePropertyName ) ) ;
if ( UFunction * Function = GetDelegateSignature ( ) )
2014-03-14 14:13:41 -04:00
{
2014-09-03 18:17:44 -04:00
const FText SignatureTooltip = Function - > GetToolTipText ( ) ;
if ( ! SignatureTooltip . IsEmpty ( ) )
{
CachedTooltip = FText : : Format ( LOCTEXT ( " DelegateSet_SubtitledTooltip " , " {0} \n {1} " ) , ( FText & ) CachedTooltip , SignatureTooltip ) ;
}
2014-03-14 14:13:41 -04:00
}
}
2014-09-03 18:17:44 -04:00
return CachedTooltip ;
2014-03-14 14:13:41 -04:00
}
2014-04-23 18:30:37 -04:00
FText UK2Node_DelegateSet : : GetNodeTitle ( ENodeTitleType : : Type TitleType ) const
2014-03-14 14:13:41 -04:00
{
2014-09-02 19:08:09 -04:00
if ( CachedNodeTitle . IsOutOfDate ( ) )
{
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " DelegatePropertyName " ) , FText : : FromName ( DelegatePropertyName ) ) ;
// FText::Format() is slow, so we cache this to save on performance
CachedNodeTitle = FText : : Format ( NSLOCTEXT ( " K2Node " , " Assign_Name " , " Assign {DelegatePropertyName} " ) , Args ) ;
}
return CachedNodeTitle ;
2014-04-23 18:30:37 -04:00
}
2014-03-14 14:13:41 -04:00
UEdGraphPin * UK2Node_DelegateSet : : GetDelegateOwner ( ) const
{
const UEdGraphSchema_K2 * K2Schema = GetDefault < UEdGraphSchema_K2 > ( ) ;
UEdGraphPin * Pin = FindPin ( DelegatePropertyName . ToString ( ) ) ;
check ( Pin ! = NULL ) ;
check ( Pin - > Direction = = EGPD_Input ) ;
return Pin ;
}
UFunction * UK2Node_DelegateSet : : GetDelegateSignature ( )
{
UMulticastDelegateProperty * DelegateProperty = FindField < UMulticastDelegateProperty > ( DelegatePropertyClass , DelegatePropertyName ) ;
if ( ! DelegateProperty )
{
// Attempt to find a remapped delegate property
UMulticastDelegateProperty * NewProperty = Cast < UMulticastDelegateProperty > ( FindRemappedField ( DelegatePropertyClass , DelegatePropertyName ) ) ;
if ( NewProperty )
{
// Found a remapped property, update the node
DelegateProperty = NewProperty ;
DelegatePropertyName = NewProperty - > GetFName ( ) ;
DelegatePropertyClass = Cast < UClass > ( NewProperty - > GetOuter ( ) ) ;
}
}
return ( DelegateProperty ! = NULL ) ? DelegateProperty - > SignatureFunction : NULL ;
}
UFunction * UK2Node_DelegateSet : : GetDelegateSignature ( ) const
{
UMulticastDelegateProperty * DelegateProperty = FindField < UMulticastDelegateProperty > ( DelegatePropertyClass , DelegatePropertyName ) ;
if ( ! DelegateProperty )
{
// Attempt to find a remapped delegate property
DelegateProperty = Cast < UMulticastDelegateProperty > ( FindRemappedField ( DelegatePropertyClass , DelegatePropertyName ) ) ;
}
return ( DelegateProperty ! = NULL ) ? DelegateProperty - > SignatureFunction : NULL ;
}
void UK2Node_DelegateSet : : ValidateNodeDuringCompilation ( class FCompilerResultsLog & MessageLog ) const
{
Super : : ValidateNodeDuringCompilation ( MessageLog ) ;
// If we are overriding a function, but we can;t find the function we are overriding, that is a compile error
if ( GetDelegateSignature ( ) = = NULL )
{
MessageLog . Error ( * FString : : Printf ( * NSLOCTEXT ( " KismetCompiler " , " MissingDelegateSig_Error " , " Unable to find delegate '%s' for @@ " ) . ToString ( ) , * DelegatePropertyName . ToString ( ) ) , this ) ;
}
}
FNodeHandlingFunctor * UK2Node_DelegateSet : : CreateNodeHandler ( FKismetCompilerContext & CompilerContext ) const
{
return new FKCHandler_BindToMulticastDelegate ( CompilerContext ) ;
}
UK2Node : : ERedirectType UK2Node_DelegateSet : : DoPinsMatchForReconstruction ( const UEdGraphPin * NewPin , int32 NewPinIndex , const UEdGraphPin * OldPin , int32 OldPinIndex ) const
{
ERedirectType OrginalResult = Super : : DoPinsMatchForReconstruction ( NewPin , NewPinIndex , OldPin , OldPinIndex ) ;
const UEdGraphSchema_K2 * K2Schema = Cast < const UEdGraphSchema_K2 > ( GetSchema ( ) ) ;
if ( ( ERedirectType : : ERedirectType_None = = OrginalResult ) & & K2Schema & & NewPin & & OldPin )
{
2014-04-23 17:58:27 -04:00
bool const bOldPinIsObj = ( OldPin - > PinType . PinCategory = = K2Schema - > PC_Object ) | | ( OldPin - > PinType . PinCategory = = K2Schema - > PC_Interface ) ;
bool const bNewPinIsObj = ( OldPin - > PinType . PinCategory = = K2Schema - > PC_Object ) | | ( OldPin - > PinType . PinCategory = = K2Schema - > PC_Interface ) ;
2014-03-14 14:13:41 -04:00
if ( ( NewPin - > Direction = = EGPD_Input & & OldPin - > Direction = = EGPD_Input ) & &
2014-04-23 17:58:27 -04:00
bOldPinIsObj & & bNewPinIsObj )
2014-03-14 14:13:41 -04:00
{
return ERedirectType_Name ;
}
}
return OrginalResult ;
}
void UK2Node_DelegateSet : : ExpandNode ( class FKismetCompilerContext & CompilerContext , UEdGraph * SourceGraph )
{
Super : : ExpandNode ( CompilerContext , SourceGraph ) ;
if ( SourceGraph ! = CompilerContext . ConsolidatedEventGraph )
{
CompilerContext . MessageLog . Error ( * FString : : Printf ( * NSLOCTEXT ( " KismetCompiler " , " InvalidNodeOutsideUbergraph_Error " , " Unexpected node @@ found outside ubergraph. " ) . ToString ( ) ) , this ) ;
}
else if ( CompilerContext . bIsFullCompile )
{
UFunction * TargetFunction = GetDelegateSignature ( ) ;
if ( TargetFunction ! = NULL )
{
const UEdGraphSchema_K2 * Schema = CompilerContext . GetSchema ( ) ;
// First, create an event node matching the delegate signature
UK2Node_Event * DelegateEvent = CompilerContext . SpawnIntermediateNode < UK2Node_Event > ( this , SourceGraph ) ;
DelegateEvent - > EventSignatureClass = Cast < UClass > ( TargetFunction - > GetOuter ( ) ) ;
DelegateEvent - > EventSignatureName = TargetFunction - > GetFName ( ) ;
DelegateEvent - > CustomFunctionName = GetDelegateTargetEntryPointName ( ) ;
DelegateEvent - > bInternalEvent = true ;
DelegateEvent - > AllocateDefaultPins ( ) ;
// Move the pins over to the newly created event node
for ( TArray < UEdGraphPin * > : : TIterator PinIt ( DelegateEvent - > Pins ) ; PinIt ; + + PinIt )
{
UEdGraphPin * CurrentPin = * PinIt ;
check ( CurrentPin ) ;
if ( CurrentPin - > Direction = = EGPD_Output )
{
if ( CurrentPin - > PinType . PinCategory = = Schema - > PC_Exec )
{
// Hook up the exec pin specially, since it has a different name on the dynamic delegate node
UEdGraphPin * OldExecPin = FindPin ( Schema - > PN_DelegateEntry ) ;
check ( OldExecPin ) ;
2014-04-23 17:45:37 -04:00
CompilerContext . MovePinLinksToIntermediate ( * OldExecPin , * CurrentPin ) ;
2014-03-14 14:13:41 -04:00
}
else if ( CurrentPin - > PinName ! = UK2Node_Event : : DelegateOutputName )
{
// Hook up all other pins, EXCEPT the delegate output pin, which isn't needed in this case
UEdGraphPin * OldPin = FindPin ( CurrentPin - > PinName ) ;
if ( ! OldPin )
{
// If we couldn't find the old pin, the function signature is out of date. Tell them to reconstruct
CompilerContext . MessageLog . Error ( * FString : : Printf ( * NSLOCTEXT ( " KismetCompiler " , " EventNodeOutOfDate_Error " , " Event node @@ is out-of-date. Please refresh it. " ) . ToString ( ) ) , this ) ;
return ;
}
2014-04-23 17:45:37 -04:00
CompilerContext . MovePinLinksToIntermediate ( * OldPin , * CurrentPin ) ;
2014-03-14 14:13:41 -04:00
}
}
}
}
else
{
CompilerContext . MessageLog . Error ( * FString : : Printf ( * LOCTEXT ( " DelegateSigNotFound_Error " , " Set Delegate node @@ unable to find function. " ) . ToString ( ) ) , this ) ;
}
}
}
# undef LOCTEXT_NAMESPACE