2016-01-07 08:17:16 -05:00
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
# include "GraphEditorCommon.h"
# include "GraphDiffControl.h"
# include "BlueprintEditorUtils.h"
# define LOCTEXT_NAMESPACE "GraphDiffControl"
//If we are collecting all Diff results, keep going. If we just want to know if there *is* any diffs, we can early out
2015-05-01 06:38:56 -04:00
# define KEEP_GOING_IF_RESULTS() bHasResult = true; \
if ( ! Results . CanStoreResults ( ) ) { break ; }
2014-03-14 14:13:41 -04:00
/*******************************************************************************
* Static helper functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/** Diff result when a node was added to the graph */
2015-05-01 06:38:56 -04:00
static void DiffR_NodeAdded ( const FGraphDiffControl : : FNodeDiffContext & DiffContext , FDiffResults & Results , UEdGraphNode * Node )
2014-03-14 14:13:41 -04:00
{
2015-05-01 06:38:56 -04:00
FDiffSingleResult Diff ;
Diff . Diff = EDiffType : : NODE_ADDED ;
Diff . Node1 = Node ;
2014-04-23 18:30:37 -04:00
2015-05-01 06:38:56 -04:00
// Only bother setting up the display data if we're storing the result
if ( Results . CanStoreResults ( ) )
{
2014-04-23 18:30:37 -04:00
FFormatNamedArguments Args ;
2015-05-01 06:38:56 -04:00
Args . Add ( TEXT ( " NodeType " ) , DiffContext . NodeTypeDisplayName ) ;
2014-04-23 18:30:37 -04:00
Args . Add ( TEXT ( " NodeTitle " ) , Node - > GetNodeTitle ( ENodeTitleType : : ListView ) ) ;
2015-05-01 06:38:56 -04:00
Diff . ToolTip = FText : : Format ( LOCTEXT ( " DIF_AddNode " , " Added {NodeType} '{NodeTitle}' " ) , Args ) ;
2014-03-14 14:13:41 -04:00
Diff . DisplayString = Diff . ToolTip ;
Diff . DisplayColor = FLinearColor ( 0.3f , 1.0f , 0.4f ) ;
}
2015-05-01 06:38:56 -04:00
Results . Add ( Diff ) ;
}
/** Diff result when a node was removed from the graph */
static void DiffR_NodeRemoved ( const FGraphDiffControl : : FNodeDiffContext & DiffContext , FDiffResults & Results , UEdGraphNode * Node )
{
FDiffSingleResult Diff ;
Diff . Diff = EDiffType : : NODE_REMOVED ;
Diff . Node1 = Node ;
// Only bother setting up the display data if we're storing the result
if ( Results . CanStoreResults ( ) )
{
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " NodeType " ) , DiffContext . NodeTypeDisplayName ) ;
Args . Add ( TEXT ( " NodeTitle " ) , Node - > GetNodeTitle ( ENodeTitleType : : ListView ) ) ;
Diff . ToolTip = FText : : Format ( LOCTEXT ( " DIF_RemoveNode " , " Removed {NodeType} '{NodeTitle}' " ) , Args ) ;
Diff . DisplayString = Diff . ToolTip ;
Diff . DisplayColor = FLinearColor ( 1.f , 0.4f , 0.4f ) ;
}
Results . Add ( Diff ) ;
2014-03-14 14:13:41 -04:00
}
/** Diff result when a node comment was changed */
2015-05-01 06:38:56 -04:00
static void DiffR_NodeCommentChanged ( const FGraphDiffControl : : FNodeDiffContext & DiffContext , FDiffResults & Results , class UEdGraphNode * Node , class UEdGraphNode * Node2 )
2014-03-14 14:13:41 -04:00
{
2015-05-01 06:38:56 -04:00
FDiffSingleResult Diff ;
Diff . Diff = EDiffType : : NODE_COMMENT ;
Diff . Node1 = Node ;
Diff . Node2 = Node2 ;
// Only bother setting up the display data if we're storing the result
if ( Results . CanStoreResults ( ) )
2014-03-14 14:13:41 -04:00
{
2014-04-23 18:30:37 -04:00
FFormatNamedArguments Args ;
2015-05-01 06:38:56 -04:00
Args . Add ( TEXT ( " NodeType " ) , DiffContext . NodeTypeDisplayName ) ;
2014-04-23 18:30:37 -04:00
Args . Add ( TEXT ( " NodeTitle " ) , Node - > GetNodeTitle ( ENodeTitleType : : ListView ) ) ;
2015-05-01 06:38:56 -04:00
Diff . ToolTip = FText : : Format ( LOCTEXT ( " DIF_CommentModified " , " Comment Modified {NodeType} '{NodeTitle}' " ) , Args ) ;
2014-03-14 14:13:41 -04:00
Diff . DisplayString = Diff . ToolTip ;
Diff . DisplayColor = FLinearColor ( 0.25f , 0.4f , 0.5f ) ;
}
2015-05-01 06:38:56 -04:00
Results . Add ( Diff ) ;
2014-03-14 14:13:41 -04:00
}
/** Diff result when a node was moved on the graph */
2015-05-01 06:38:56 -04:00
static void DiffR_NodeMoved ( const FGraphDiffControl : : FNodeDiffContext & DiffContext , FDiffResults & Results , UEdGraphNode * Node , class UEdGraphNode * OtherNode )
2014-03-14 14:13:41 -04:00
{
2015-05-01 06:38:56 -04:00
FDiffSingleResult Diff ;
Diff . Diff = EDiffType : : NODE_MOVED ;
Diff . Node1 = Node ;
Diff . Node2 = OtherNode ;
// Only bother setting up the display data if we're storing the result
if ( Results . CanStoreResults ( ) )
2014-03-14 14:13:41 -04:00
{
2014-04-23 18:30:37 -04:00
FFormatNamedArguments Args ;
2015-05-01 06:38:56 -04:00
Args . Add ( TEXT ( " NodeType " ) , DiffContext . NodeTypeDisplayName ) ;
2014-04-23 18:30:37 -04:00
Args . Add ( TEXT ( " NodeTitle " ) , Node - > GetNodeTitle ( ENodeTitleType : : ListView ) ) ;
2015-05-01 06:38:56 -04:00
Diff . ToolTip = FText : : Format ( LOCTEXT ( " DIF_MoveNode " , " Moved {NodeType} '{NodeTitle}' " ) , Args ) ;
2014-03-14 14:13:41 -04:00
Diff . DisplayString = Diff . ToolTip ;
Diff . DisplayColor = FLinearColor ( 0.9f , 0.84f , 0.43f ) ;
}
2015-05-01 06:38:56 -04:00
Results . Add ( Diff ) ;
2014-03-14 14:13:41 -04:00
}
/** Diff result when a pin type was changed */
static void DiffR_PinTypeChanged ( FDiffResults & Results , class UEdGraphPin * Pin2 , class UEdGraphPin * Pin1 )
{
2015-05-01 06:38:56 -04:00
FEdGraphPinType Type1 = Pin1 - > PinType ;
FEdGraphPinType Type2 = Pin2 - > PinType ;
FDiffSingleResult Diff ;
const UObject * T1Obj = Type1 . PinSubCategoryObject . Get ( ) ;
const UObject * T2Obj = Type2 . PinSubCategoryObject . Get ( ) ;
if ( Type1 . PinCategory ! = Type2 . PinCategory )
2014-03-14 14:13:41 -04:00
{
2015-05-01 06:38:56 -04:00
Diff . Diff = EDiffType : : PIN_TYPE_CATEGORY ;
2014-03-14 14:13:41 -04:00
2015-05-01 06:38:56 -04:00
// Only bother setting up the display data if we're storing the result
if ( Results . CanStoreResults ( ) )
2014-03-14 14:13:41 -04:00
{
2015-01-07 09:52:40 -05:00
Diff . ToolTip = FText : : Format ( LOCTEXT ( " DIF_PinCategoryToolTipFmt " , " Pin '{0}' Category was '{1}', but is now '{2} " ) , FText : : FromString ( Pin2 - > PinName ) , FText : : FromString ( Pin1 - > PinType . PinCategory ) , FText : : FromString ( Pin2 - > PinType . PinCategory ) ) ;
2014-03-14 14:13:41 -04:00
Diff . DisplayColor = FLinearColor ( 0.15f , 0.53f , 0.15f ) ;
2015-01-07 09:52:40 -05:00
Diff . DisplayString = FText : : Format ( LOCTEXT ( " DIF_PinCategoryFmt " , " Pin Category '{0}' ['{1}' -> '{2}'] " ) , FText : : FromString ( Pin2 - > PinName ) , FText : : FromString ( Pin1 - > PinType . PinCategory ) , FText : : FromString ( Pin2 - > PinType . PinCategory ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-05-01 06:38:56 -04:00
}
else if ( Type1 . PinSubCategory ! = Type2 . PinSubCategory )
{
Diff . Diff = EDiffType : : PIN_TYPE_SUBCATEGORY ;
// Only bother setting up the display data if we're storing the result
if ( Results . CanStoreResults ( ) )
2014-03-14 14:13:41 -04:00
{
2015-01-07 09:52:40 -05:00
Diff . ToolTip = FText : : Format ( LOCTEXT ( " DIF_PinSubCategoryToolTipFmt " , " Pin '{0}' SubCategory was '{1}', but is now '{2} " ) , FText : : FromString ( Pin2 - > PinName ) , FText : : FromString ( Pin1 - > PinType . PinSubCategory ) , FText : : FromString ( Pin2 - > PinType . PinSubCategory ) ) ;
2014-03-14 14:13:41 -04:00
Diff . DisplayColor = FLinearColor ( 0.45f , 0.53f , 0.65f ) ;
2015-01-07 09:52:40 -05:00
Diff . DisplayString = FText : : Format ( LOCTEXT ( " DIF_PinSubCategoryFmt " , " Pin SubCategory '{0}' ['{1}' -> '{2}'] " ) , FText : : FromString ( Pin2 - > PinName ) , FText : : FromString ( Pin1 - > PinType . PinSubCategory ) , FText : : FromString ( Pin2 - > PinType . PinSubCategory ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-05-01 06:38:56 -04:00
}
else if ( T1Obj ! = T2Obj & & ( T1Obj & & T2Obj ) & &
( T1Obj - > GetFName ( ) ! = T2Obj - > GetFName ( ) ) )
{
Diff . Diff = EDiffType : : PIN_TYPE_SUBCATEGORY_OBJECT ;
// Only bother setting up the display data if we're storing the result
if ( Results . CanStoreResults ( ) )
2014-03-14 14:13:41 -04:00
{
FString Obj1 = T1Obj - > GetFName ( ) . ToString ( ) ;
FString Obj2 = T2Obj - > GetFName ( ) . ToString ( ) ;
2015-01-07 09:52:40 -05:00
Diff . ToolTip = FText : : Format ( LOCTEXT ( " DIF_PinSubCategorObjToolTipFmt " , " Pin '{0}' was SubCategoryObject '{1}', but is now '{2} " ) , FText : : FromString ( Pin2 - > PinName ) , FText : : FromString ( Obj1 ) , FText : : FromString ( Obj2 ) ) ;
2014-03-14 14:13:41 -04:00
Diff . DisplayColor = FLinearColor ( 0.45f , 0.13f , 0.25f ) ;
2015-01-07 09:52:40 -05:00
Diff . DisplayString = FText : : Format ( LOCTEXT ( " DIF_PinSubCategoryObjFmt " , " Pin SubCategoryObject '{0}' ['{1}' -> '{2}'] " ) , FText : : FromString ( Pin2 - > PinName ) , FText : : FromString ( Obj1 ) , FText : : FromString ( Obj2 ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-05-01 06:38:56 -04:00
}
else if ( Type1 . bIsArray ! = Type2 . bIsArray )
{
Diff . Diff = EDiffType : : PIN_TYPE_IS_ARRAY ;
// Only bother setting up the display data if we're storing the result
if ( Results . CanStoreResults ( ) )
2014-03-14 14:13:41 -04:00
{
2015-01-07 09:52:40 -05:00
FText IsArray1 = Pin1 - > PinType . bIsArray ? LOCTEXT ( " true " , " true " ) : LOCTEXT ( " false " , " false " ) ;
FText IsArray2 = Pin2 - > PinType . bIsArray ? LOCTEXT ( " true " , " true " ) : LOCTEXT ( " false " , " false " ) ;
2014-03-14 14:13:41 -04:00
2015-01-07 09:52:40 -05:00
Diff . ToolTip = FText : : Format ( LOCTEXT ( " DIF_PinIsArrayToolTipFmt " , " PinType IsArray for '{0}' modified. Was '{1}', but is now '{2} " ) , FText : : FromString ( Pin2 - > PinName ) , IsArray1 , IsArray2 ) ;
Diff . DisplayString = FText : : Format ( LOCTEXT ( " DIF_PinIsArrayFmt " , " Pin IsArray '{0}' ['{1}' -> '{2}'] " ) , FText : : FromString ( Pin2 - > PinName ) , IsArray1 , IsArray2 ) ;
2014-03-14 14:13:41 -04:00
Diff . DisplayColor = FLinearColor ( 0.45f , 0.33f , 0.35f ) ;
}
2015-05-01 06:38:56 -04:00
}
else if ( Type1 . bIsReference ! = Type2 . bIsReference )
{
Diff . Diff = EDiffType : : PIN_TYPE_IS_REF ;
// Only bother setting up the display data if we're storing the result
if ( Results . CanStoreResults ( ) )
2014-03-14 14:13:41 -04:00
{
2015-01-07 09:52:40 -05:00
FText IsRef1 = Pin1 - > PinType . bIsReference ? LOCTEXT ( " true " , " true " ) : LOCTEXT ( " false " , " false " ) ;
FText IsRef2 = Pin2 - > PinType . bIsReference ? LOCTEXT ( " true " , " true " ) : LOCTEXT ( " false " , " false " ) ;
2014-03-14 14:13:41 -04:00
2015-01-07 09:52:40 -05:00
Diff . ToolTip = FText : : Format ( LOCTEXT ( " DIF_PinIsRefToolTipFmt " , " PinType IsReference for '{0}' modified. Was '{1}', but is now '{2} " ) , FText : : FromString ( Pin2 - > PinName ) , IsRef1 , IsRef2 ) ;
2014-03-14 14:13:41 -04:00
Diff . DisplayColor = FLinearColor ( 0.25f , 0.43f , 0.35f ) ;
2015-01-07 09:52:40 -05:00
Diff . DisplayString = FText : : Format ( LOCTEXT ( " DIF_PinIsRefFmt " , " Pin IsReference '{0}' ['{1}' -> '{2}'] " ) , FText : : FromString ( Pin2 - > PinName ) , IsRef1 , IsRef2 ) ;
2014-03-14 14:13:41 -04:00
}
}
2015-05-01 06:38:56 -04:00
Diff . Pin1 = Pin1 ;
Diff . Pin2 = Pin2 ;
Results . Add ( Diff ) ;
2014-03-14 14:13:41 -04:00
}
/** Diff result when the # of links to a pin was changed */
static void DiffR_PinLinkCountChanged ( FDiffResults & Results , class UEdGraphPin * Pin2 , class UEdGraphPin * Pin1 )
{
2015-05-01 06:38:56 -04:00
FDiffSingleResult Diff ;
Diff . Diff = Pin2 - > LinkedTo . Num ( ) > Pin1 - > LinkedTo . Num ( ) ? EDiffType : : PIN_LINKEDTO_NUM_INC : EDiffType : : PIN_LINKEDTO_NUM_DEC ;
Diff . Pin2 = Pin2 ;
Diff . Pin1 = Pin1 ;
// Only bother setting up the display data if we're storing the result
if ( Results . CanStoreResults ( ) )
2014-03-14 14:13:41 -04:00
{
if ( Diff . Diff = = EDiffType : : PIN_LINKEDTO_NUM_INC )
{
2015-01-07 09:52:40 -05:00
Diff . ToolTip = FText : : Format ( LOCTEXT ( " DIF_PinLinkCountIncToolTipFmt " , " Pin '{0}' has more links (was {1} now {2}) " ) , FText : : FromString ( Pin1 - > PinName ) , FText : : AsNumber ( Pin1 - > LinkedTo . Num ( ) ) , FText : : AsNumber ( Pin2 - > LinkedTo . Num ( ) ) ) ;
2014-03-14 14:13:41 -04:00
Diff . DisplayColor = FLinearColor ( 0.5f , 0.3f , 0.85f ) ;
2015-01-07 09:52:40 -05:00
Diff . DisplayString = FText : : Format ( LOCTEXT ( " DIF_PinLinkCountIncFmt " , " Added Link to '{0}' " ) , FText : : FromString ( Pin1 - > PinName ) ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2015-01-07 09:52:40 -05:00
Diff . ToolTip = FText : : Format ( LOCTEXT ( " DIF_PinLinkCountDecToolTipFmt " , " Pin '{0}' has fewer links (was {1} now {2}) " ) , FText : : FromString ( Pin1 - > PinName ) , FText : : AsNumber ( Pin1 - > LinkedTo . Num ( ) ) , FText : : AsNumber ( Pin2 - > LinkedTo . Num ( ) ) ) ;
2014-03-14 14:13:41 -04:00
Diff . DisplayColor = FLinearColor ( 0.5f , 0.3f , 0.85f ) ;
2015-01-07 09:52:40 -05:00
Diff . DisplayString = FText : : Format ( LOCTEXT ( " DIF_PinLinkCountDecFmt " , " Removed Link to '{0}' " ) , FText : : FromString ( Pin1 - > PinName ) ) ;
2014-03-14 14:13:41 -04:00
}
}
2015-05-01 06:38:56 -04:00
Results . Add ( Diff ) ;
2014-03-14 14:13:41 -04:00
}
/** Diff result when a pin to relinked to a different node */
static void DiffR_LinkedToNode ( FDiffResults & Results , class UEdGraphPin * Pin1 , class UEdGraphPin * Pin2 , class UEdGraphNode * Node1 , class UEdGraphNode * Node2 )
{
2015-05-01 06:38:56 -04:00
FDiffSingleResult Diff ;
Diff . Diff = EDiffType : : PIN_LINKEDTO_NODE ;
Diff . Pin2 = Pin2 ;
Diff . Pin1 = Pin1 ;
Diff . Node1 = Node1 ;
Diff . Node2 = Node2 ;
2014-03-14 14:13:41 -04:00
2015-05-01 06:38:56 -04:00
// Only bother setting up the display data if we're storing the result
if ( Results . CanStoreResults ( ) )
{
2014-04-23 18:30:37 -04:00
FText Node1Name = Node1 - > GetNodeTitle ( ENodeTitleType : : ListView ) ;
FText Node2Name = Node2 - > GetNodeTitle ( ENodeTitleType : : ListView ) ;
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " PinNameForNode1 " ) , FText : : FromString ( Pin1 - > PinName ) ) ;
Args . Add ( TEXT ( " NodeName1 " ) , Node1Name ) ;
Args . Add ( TEXT ( " NodeName2 " ) , Node2Name ) ;
2015-01-07 09:52:40 -05:00
Diff . ToolTip = FText : : Format ( LOCTEXT ( " DIF_PinLinkMovedToolTip " , " Pin '{PinNameForNode1}' was linked to Node '{NodeName1}', but is now linked to Node '{NodeName2}' " ) , Args ) ;
2014-04-23 18:30:37 -04:00
2014-03-14 14:13:41 -04:00
Diff . DisplayColor = FLinearColor ( 0.85f , 0.71f , 0.25f ) ;
2015-01-07 09:52:40 -05:00
Diff . DisplayString = FText : : Format ( LOCTEXT ( " DIF_PinLinkMoved " , " Link Moved '{PinNameForNode1}' ['{NodeName1}' -> '{NodeName2}'] " ) , Args ) ;
2014-03-14 14:13:41 -04:00
}
2015-05-01 06:38:56 -04:00
Results . Add ( Diff ) ;
2014-03-14 14:13:41 -04:00
}
/** Diff result when a pin default value was changed, and is in use*/
static void DiffR_PinDefaultValueChanged ( FDiffResults & Results , class UEdGraphPin * Pin2 , class UEdGraphPin * Pin1 )
{
2015-05-01 06:38:56 -04:00
FDiffSingleResult Diff ;
Diff . Diff = EDiffType : : PIN_DEFAULT_VALUE ;
Diff . Pin1 = Pin1 ;
Diff . Pin2 = Pin2 ;
2014-04-23 18:30:37 -04:00
2015-05-01 06:38:56 -04:00
// Only bother setting up the display data if we're storing the result
if ( Results . CanStoreResults ( ) )
{
2014-04-23 18:30:37 -04:00
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " PinNameForValue1 " ) , FText : : FromString ( Pin2 - > PinName ) ) ;
Args . Add ( TEXT ( " PinValue1 " ) , FText : : FromString ( Pin1 - > GetDefaultAsString ( ) ) ) ;
Args . Add ( TEXT ( " PinValue2 " ) , FText : : FromString ( Pin2 - > GetDefaultAsString ( ) ) ) ;
2015-01-07 09:52:40 -05:00
Diff . ToolTip = FText : : Format ( LOCTEXT ( " DIF_PinDefaultValueToolTip " , " Pin '{PinNameForValue1}' Default Value was '{PinValue1}', but is now '{PinValue2} " ) , Args ) ;
2014-03-14 14:13:41 -04:00
Diff . DisplayColor = FLinearColor ( 0.665f , 0.13f , 0.455f ) ;
2015-01-07 09:52:40 -05:00
Diff . DisplayString = FText : : Format ( LOCTEXT ( " DIF_PinDefaultValue " , " Pin Default '{PinNameForValue1}' '{PinValue1}' -> '{PinValue2}'] " ) , Args ) ;
2014-03-14 14:13:41 -04:00
}
2015-05-01 06:38:56 -04:00
Results . Add ( Diff ) ;
2014-03-14 14:13:41 -04:00
}
/**
* Diff result when pin count is not the same .
*
* @ param Result Struct to receive result .
* @ param Node Node 1 to which the pins relate .
* @ param Node2 Node 2 to which the pins relate .
* @ param Pins1 Array of relevant pins on Node 1.
* @ param Pins2 Array of relevant pins on Node 2.
*/
static void DiffR_NodePinCount ( FDiffResults & Results , class UEdGraphNode * Node , class UEdGraphNode * Node2 , const TArray < class UEdGraphPin * > & Pins1 , const TArray < class UEdGraphPin * > & Pins2 )
{
2015-05-01 06:38:56 -04:00
FText NodeName = Node - > GetNodeTitle ( ENodeTitleType : : ListView ) ;
int32 OriginalCount = Pins2 . Num ( ) ;
int32 NewCount = Pins1 . Num ( ) ;
FDiffSingleResult Diff ;
Diff . Diff = EDiffType : : NODE_PIN_COUNT ;
Diff . Node1 = Node ;
Diff . Node2 = Node2 ;
2014-04-23 18:30:37 -04:00
2015-05-01 06:38:56 -04:00
// Only bother setting up the display data if we're storing the result
if ( Results . CanStoreResults ( ) )
{
2014-04-23 18:30:37 -04:00
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " NodeName " ) , NodeName ) ;
Args . Add ( TEXT ( " OriginalCount " ) , OriginalCount ) ;
Args . Add ( TEXT ( " NewCount " ) , NewCount ) ;
2014-03-14 14:13:41 -04:00
Diff . DisplayColor = FLinearColor ( 0.45f , 0.4f , 0.4f ) ;
2015-08-19 20:55:56 -04:00
struct FMatchName
{
FMatchName ( const FString & InPinName )
: PinName ( InPinName )
{
}
const FString & PinName ;
bool operator ( ) ( const UEdGraphPin * Entry )
{
return PinName = = Entry - > PinName ;
}
} ;
FText ListOfPins ;
TArray < FText > RemovedPins ;
for ( auto OldPin : Pins1 )
{
const UEdGraphPin * const * FoundPin = Pins2 . FindByPredicate ( FMatchName ( OldPin - > PinName ) ) ;
if ( FoundPin = = nullptr )
{
RemovedPins . Add ( OldPin - > GetDisplayName ( ) ) ;
}
}
TArray < FText > AddedPins ;
for ( auto OldPin : Pins2 )
{
const UEdGraphPin * const * FoundPin = Pins1 . FindByPredicate ( FMatchName ( OldPin - > PinName ) ) ;
if ( FoundPin = = nullptr )
{
AddedPins . Add ( OldPin - > GetDisplayName ( ) ) ;
}
}
if ( RemovedPins . Num ( ) > 0 & & AddedPins . Num ( ) > 0 )
{
Diff . DisplayString = FText : : Format ( LOCTEXT ( " DIF_NodePinsAddedAndRemoved " , " Added and removed Pins from '{NodeName}' " ) , Args ) ;
}
else if ( AddedPins . Num ( ) > 0 )
{
if ( AddedPins . Num ( ) = = 1 )
{
Diff . DisplayString = FText : : Format ( LOCTEXT ( " DIF_NodePinCountIncreased " , " Added Pin to '{NodeName}' " ) , Args ) ;
}
else
{
Diff . DisplayString = FText : : Format ( LOCTEXT ( " DIF_NodePinCountIncreasedSeveral " , " Added Pins to '{NodeName}' " ) , Args ) ;
}
}
else if ( RemovedPins . Num ( ) > 0 )
{
if ( RemovedPins . Num ( ) = = 1 )
{
Diff . DisplayString = FText : : Format ( LOCTEXT ( " DIF_NodePinCountDecreased " , " Removed Pin from '{NodeName}' " ) , Args ) ;
}
else
{
Diff . DisplayString = FText : : Format ( LOCTEXT ( " DIF_NodePinCountDecreasedSeveral " , " Removed Pins from '{NodeName}' " ) , Args ) ;
}
}
FTextBuilder Builder ;
Builder . AppendLine ( FText : : Format ( LOCTEXT ( " DIF_NodePinCountChangedToolTip " , " Node '{NodeName}' had {OriginalCount} Pins, now has {NewCount} Pins " ) , Args ) ) ;
if ( AddedPins . Num ( ) > 0 )
{
Builder . AppendLine ( LOCTEXT ( " DIF_PinsAddedList " , " Pins Added: " ) ) ;
for ( const auto & Added : AddedPins )
{
Builder . AppendLine ( Added ) ;
}
}
if ( RemovedPins . Num ( ) > 0 )
{
Builder . AppendLine ( LOCTEXT ( " DIF_PinsRemovedList " , " Pins Removed: " ) ) ;
for ( const auto & Removed : RemovedPins )
{
Builder . AppendLine ( Removed ) ;
}
}
Diff . ToolTip = Builder . ToText ( ) ;
2014-03-14 14:13:41 -04:00
}
2015-05-01 06:38:56 -04:00
Results . Add ( Diff ) ;
2014-03-14 14:13:41 -04:00
}
/**
* Populate an array one of pins from another disregarding irrelevant ones ( EG invisible ) .
*
* @ param InPins Pins
* @ param OutRelevanPins Output of Relevant pins
*/
static void BuildArrayOfRelevantPins ( const TArray < class UEdGraphPin * > & InPins , TArray < UEdGraphPin * > & OutRelevantPins )
{
for ( int32 i = 0 ; i < InPins . Num ( ) ; + + i )
{
UEdGraphPin * EachPin = InPins [ i ] ;
if ( EachPin ! = NULL )
{
if ( EachPin - > bHidden = = false )
{
OutRelevantPins . Add ( EachPin ) ;
}
}
}
}
static bool IsPinTypeDifferent ( const FEdGraphPinType & T1 , const FEdGraphPinType & T2 )
{
bool bIsDifferent = ( T1 . PinCategory ! = T2 . PinCategory )
| | ( T1 . PinSubCategory ! = T2 . PinSubCategory )
| | ( T1 . bIsArray ! = T2 . bIsArray )
| | ( T1 . bIsReference ! = T2 . bIsReference ) ;
const UObject * T1Obj = T1 . PinSubCategoryObject . Get ( ) ;
const UObject * T2Obj = T2 . PinSubCategoryObject . Get ( ) ;
//TODO: fix, this code makes no sense
if ( ( T1Obj ! = T2Obj ) & & ( T1Obj & & T2Obj ) & & ( T1Obj - > GetFName ( ) ! = T2Obj - > GetFName ( ) ) )
{
bIsDifferent | = T1Obj - > GetFName ( ) = = T2Obj - > GetFName ( ) ;
}
return bIsDifferent ;
}
/** Find Pin in array that matches pin */
static class UEdGraphPin * FindOtherLink ( TArray < class UEdGraphPin * > & Links2 , int32 OriginalIndex , class UEdGraphPin * PinToFind )
{
//sometimes the order of the pins is different between revisions, although the pins themselves are unchanged, so we have to look at all of them
UEdGraphNode * Node1 = PinToFind - > GetOwningNode ( ) ;
for ( auto It ( Links2 . CreateIterator ( ) ) ; It ; + + It )
{
UEdGraphPin * Other = * It ;
UEdGraphNode * Node2 = Other - > GetOwningNode ( ) ;
2015-05-01 06:38:56 -04:00
if ( FGraphDiffControl : : IsNodeMatch ( Node1 , Node2 ) )
2014-03-14 14:13:41 -04:00
{
return Other ;
}
}
return Links2 [ OriginalIndex ] ;
}
/** Determine if the LinkedTo pins are the same */
static bool LinkedToDifferent ( class UEdGraphPin * OriginalPin1 , class UEdGraphPin * OriginalPin2 , const TArray < class UEdGraphPin * > & Links1 , TArray < class UEdGraphPin * > & Links2 , FDiffResults & Results )
{
const int32 Size = Links1 . Num ( ) ;
bool bHasResult = false ;
for ( int32 i = 0 ; i < Size ; + + i )
{
UEdGraphPin * Pin1 = Links1 [ i ] ;
UEdGraphPin * Pin2 = FindOtherLink ( Links2 , i , Pin1 ) ;
UEdGraphNode * Node1 = Pin1 - > GetOwningNode ( ) ;
UEdGraphNode * Node2 = Pin2 - > GetOwningNode ( ) ;
2015-05-01 06:38:56 -04:00
if ( ! FGraphDiffControl : : IsNodeMatch ( Node1 , Node2 ) )
2014-03-14 14:13:41 -04:00
{
DiffR_LinkedToNode ( Results , OriginalPin1 , OriginalPin2 , Node1 , Node2 ) ;
KEEP_GOING_IF_RESULTS ( )
}
}
return bHasResult ;
}
/**
* Determine of two Arrays of Pins are different .
*
* @ param Pins1 First set of pins to compare .
* @ param Pins2 Second set of pins to compare .
* @ param Results Difference results .
*
* returns true if any pins are different and populates the Results array
*/
static bool ArePinsDifferent ( const TArray < class UEdGraphPin * > & Pins1 , TArray < class UEdGraphPin * > & Pins2 , FDiffResults & Results )
{
const int32 Size = Pins1 . Num ( ) ;
bool bHasResult = false ;
for ( int32 i = 0 ; i < Size ; + + i )
{
UEdGraphPin * Pin1 = Pins1 [ i ] ;
UEdGraphPin * Pin2 = Pins2 [ i ] ;
if ( IsPinTypeDifferent ( Pin1 - > PinType , Pin2 - > PinType ) )
{
DiffR_PinTypeChanged ( Results , Pin2 , Pin1 ) ;
KEEP_GOING_IF_RESULTS ( )
}
if ( Pin1 - > LinkedTo . Num ( ) ! = Pin2 - > LinkedTo . Num ( ) )
{
DiffR_PinLinkCountChanged ( Results , Pin2 , Pin1 ) ;
KEEP_GOING_IF_RESULTS ( )
}
else if ( LinkedToDifferent ( Pin1 , Pin2 , Pin1 - > LinkedTo , Pin2 - > LinkedTo , Results ) )
{
KEEP_GOING_IF_RESULTS ( )
}
if ( Pin2 - > LinkedTo . Num ( ) = = 0 & & ( Pin2 - > GetDefaultAsString ( ) ! = Pin1 - > GetDefaultAsString ( ) ) )
{
DiffR_PinDefaultValueChanged ( Results , Pin2 , Pin1 ) ; //note: some issues with how floating point is stored as string format(0.0 vs 0.00) can cause false diffs
KEEP_GOING_IF_RESULTS ( )
}
}
return bHasResult ;
}
/*******************************************************************************
* FGraphDiffControl : : FNodeMatch
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool FGraphDiffControl : : FNodeMatch : : IsValid ( ) const
{
return ( ( NewNode ! = NULL ) & & ( OldNode ! = NULL ) ) ;
}
2015-05-01 06:38:56 -04:00
bool FGraphDiffControl : : FNodeMatch : : Diff ( const FNodeDiffContext & DiffContext , TArray < FDiffSingleResult > * OptionalDiffsArray /* = NULL*/ ) const
2014-03-14 14:13:41 -04:00
{
FDiffResults DiffsOut ( OptionalDiffsArray ) ;
2015-05-01 06:38:56 -04:00
return Diff ( DiffContext , DiffsOut ) ;
}
bool FGraphDiffControl : : FNodeMatch : : Diff ( const FNodeDiffContext & DiffContext , FDiffResults & DiffsOut ) const
{
2014-03-14 14:13:41 -04:00
bool bIsDifferent = false ;
if ( IsValid ( ) )
{
//has comment changed?
2015-05-01 06:38:56 -04:00
if ( ( DiffContext . DiffFlags & EDiffFlags : : NodeComment ) & & NewNode - > NodeComment ! = OldNode - > NodeComment )
2014-03-14 14:13:41 -04:00
{
2015-05-01 06:38:56 -04:00
DiffR_NodeCommentChanged ( DiffContext , DiffsOut , NewNode , OldNode ) ;
2014-03-14 14:13:41 -04:00
bIsDifferent = true ;
}
//has it moved?
2015-05-01 06:38:56 -04:00
if ( ( DiffContext . DiffFlags & EDiffFlags : : NodeMovement ) & & ( ( NewNode - > NodePosX ! = OldNode - > NodePosX ) | | ( NewNode - > NodePosY ! = OldNode - > NodePosY ) ) )
2014-03-14 14:13:41 -04:00
{
//same node, different position--
2015-05-01 06:38:56 -04:00
DiffR_NodeMoved ( DiffContext , DiffsOut , NewNode , OldNode ) ;
2014-03-14 14:13:41 -04:00
bIsDifferent = true ;
}
2015-05-01 06:38:56 -04:00
if ( DiffContext . DiffFlags & EDiffFlags : : NodePins )
{
// Build arrays of pins that we care about
TArray < UEdGraphPin * > OldRelevantPins ;
TArray < UEdGraphPin * > RelevantPins ;
BuildArrayOfRelevantPins ( OldNode - > Pins , OldRelevantPins ) ;
BuildArrayOfRelevantPins ( NewNode - > Pins , RelevantPins ) ;
2014-03-14 14:13:41 -04:00
2015-05-01 06:38:56 -04:00
if ( OldRelevantPins . Num ( ) = = RelevantPins . Num ( ) )
{
//checks contents of pins
bIsDifferent | = ArePinsDifferent ( OldRelevantPins , RelevantPins , DiffsOut ) ;
}
else //# of pins changed
{
DiffR_NodePinCount ( DiffsOut , NewNode , OldNode , RelevantPins , OldRelevantPins ) ;
bIsDifferent = true ;
}
2014-03-14 14:13:41 -04:00
}
//Find internal node diffs; skip this if we don't need the result data
2015-05-01 06:38:56 -04:00
if ( ( DiffContext . DiffFlags & EDiffFlags : : NodeSpecificDiffs ) & & ( ! bIsDifferent | | DiffsOut . CanStoreResults ( ) ) )
2014-03-14 14:13:41 -04:00
{
OldNode - > FindDiffs ( NewNode , DiffsOut ) ;
bIsDifferent | = DiffsOut . HasFoundDiffs ( ) ;
}
}
2015-05-01 06:38:56 -04:00
else if ( DiffContext . DiffFlags & EDiffFlags : : NodeExistance )
2014-03-14 14:13:41 -04:00
// one of the nodes is NULL
{
bIsDifferent = true ;
2015-05-01 06:38:56 -04:00
switch ( DiffContext . DiffMode )
{
case EDiffMode : : Additive :
DiffR_NodeAdded ( DiffContext , DiffsOut , NewNode ) ;
break ;
case EDiffMode : : Subtractive :
DiffR_NodeRemoved ( DiffContext , DiffsOut , NewNode ) ;
break ;
default :
break ;
}
2014-03-14 14:13:41 -04:00
}
return bIsDifferent ;
}
/*******************************************************************************
* FGraphDiffControl
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
FGraphDiffControl : : FNodeMatch FGraphDiffControl : : FindNodeMatch ( class UEdGraph * Graph , class UEdGraphNode * Node , TArray < FNodeMatch > const & PriorMatches )
{
FNodeMatch Match ;
Match . NewNode = Node ;
if ( Graph ! = NULL )
{
// attempt to find a node matching 'Node'
for ( auto NodeIt ( Graph - > Nodes . CreateIterator ( ) ) ; NodeIt ; + + NodeIt )
{
UEdGraphNode * GraphNode = * NodeIt ;
if ( GraphNode = = NULL )
{
continue ;
}
if ( IsNodeMatch ( Node , GraphNode , & PriorMatches ) )
{
Match . OldNode = GraphNode ;
break ;
}
}
}
return Match ;
}
2015-05-01 06:38:56 -04:00
bool FGraphDiffControl : : IsNodeMatch ( class UEdGraphNode * Node1 , class UEdGraphNode * Node2 , TArray < FGraphDiffControl : : FNodeMatch > const * Exclusions )
{
if ( Node2 - > GetClass ( ) ! = Node1 - > GetClass ( ) )
{
return false ;
}
if ( Node1 - > NodeGuid = = Node2 - > NodeGuid )
{
return true ;
}
// we could be diffing two completely separate assets, this makes sure both
// nodes historically belong to the same graph
bool bIsIntraAssetDiff = ( Node1 - > GetGraph ( ) - > GraphGuid = = Node2 - > GetGraph ( ) - > GraphGuid ) ;
// if both nodes are from the same graph
if ( bIsIntraAssetDiff )
{
return ( Node1 - > GetFName ( ) = = Node2 - > GetFName ( ) ) ;
}
if ( Exclusions ! = NULL )
{
// have to see if this node has already been matched with another
for ( auto MatchIt ( Exclusions - > CreateConstIterator ( ) ) ; MatchIt ; + + MatchIt )
{
FGraphDiffControl : : FNodeMatch const & PriorMatch = * MatchIt ;
if ( ! PriorMatch . IsValid ( ) )
{
continue ;
}
// if one of these nodes has already been matched to a different node
if ( ( ( PriorMatch . OldNode = = Node1 ) & & ( PriorMatch . NewNode ! = Node2 ) ) | |
( ( PriorMatch . OldNode = = Node2 ) & & ( PriorMatch . NewNode ! = Node1 ) ) | |
( ( PriorMatch . NewNode = = Node1 ) & & ( PriorMatch . OldNode ! = Node2 ) ) | |
( ( PriorMatch . NewNode = = Node2 ) & & ( PriorMatch . OldNode ! = Node1 ) ) )
{
return false ;
}
}
}
// the name hashes won't match for nodes from separate graph assets, so we
// need to look for some kind of semblance between the two... title? (what's displayed to the user)
FText Title1 = Node1 - > GetNodeTitle ( ENodeTitleType : : FullTitle ) ;
FText Title2 = Node2 - > GetNodeTitle ( ENodeTitleType : : FullTitle ) ;
return Title1 . CompareTo ( Title2 ) = = 0 ;
}
2014-03-14 14:13:41 -04:00
bool FGraphDiffControl : : DiffGraphs ( UEdGraph * const LhsGraph , UEdGraph * const RhsGraph , TArray < FDiffSingleResult > & DiffsOut )
{
bool bFoundDifferences = false ;
if ( ( LhsGraph ! = NULL ) & & ( RhsGraph ! = NULL ) )
{
TArray < FGraphDiffControl : : FNodeMatch > NodeMatches ;
TSet < UEdGraphNode const * > MatchedRhsNodes ;
2015-05-01 06:38:56 -04:00
FGraphDiffControl : : FNodeDiffContext AdditiveDiffContext ;
AdditiveDiffContext . NodeTypeDisplayName = LOCTEXT ( " NodeDiffDisplayName " , " Node " ) ;
2014-06-23 04:56:29 -04:00
// march through the all the nodes in the rhs graph and look for matches
for ( auto NodeIt ( RhsGraph - > Nodes . CreateConstIterator ( ) ) ; NodeIt ; + + NodeIt )
2014-03-14 14:13:41 -04:00
{
2014-06-23 04:56:29 -04:00
UEdGraphNode * const RhsNode = * NodeIt ;
if ( RhsNode = = NULL )
2014-03-14 14:13:41 -04:00
{
continue ;
}
2014-06-23 04:56:29 -04:00
FGraphDiffControl : : FNodeMatch NodeMatch = FGraphDiffControl : : FindNodeMatch ( LhsGraph , RhsNode , NodeMatches ) ;
// if we found a corresponding node in the lhs graph, track it (so we
2014-03-14 14:13:41 -04:00
// can prevent future matches with the same nodes)
if ( NodeMatch . IsValid ( ) )
{
NodeMatches . Add ( NodeMatch ) ;
MatchedRhsNodes . Add ( NodeMatch . OldNode ) ;
}
2015-05-01 06:38:56 -04:00
bFoundDifferences | = NodeMatch . Diff ( AdditiveDiffContext , & DiffsOut ) ;
2014-03-14 14:13:41 -04:00
}
2015-05-01 06:38:56 -04:00
FGraphDiffControl : : FNodeDiffContext SubtractiveDiffContext = AdditiveDiffContext ;
SubtractiveDiffContext . DiffMode = EDiffMode : : Subtractive ;
SubtractiveDiffContext . DiffFlags = EDiffFlags : : NodeExistance ;
2014-06-23 04:56:29 -04:00
// go through the lhs nodes to catch ones that may have been missing from the rhs graph
for ( auto NodeIt ( LhsGraph - > Nodes . CreateConstIterator ( ) ) ; NodeIt ; + + NodeIt )
2014-03-14 14:13:41 -04:00
{
2014-06-23 04:56:29 -04:00
UEdGraphNode * const LhsNode = * NodeIt ;
2014-03-14 14:13:41 -04:00
// if this node has already been matched, move on
2014-06-23 04:56:29 -04:00
if ( ( LhsNode = = NULL ) | | MatchedRhsNodes . Find ( LhsNode ) )
2014-03-14 14:13:41 -04:00
{
continue ;
}
2014-06-23 04:56:29 -04:00
FGraphDiffControl : : FNodeMatch NodeMatch = FGraphDiffControl : : FindNodeMatch ( RhsGraph , LhsNode , NodeMatches ) ;
2015-05-01 06:38:56 -04:00
bFoundDifferences | = NodeMatch . Diff ( SubtractiveDiffContext , & DiffsOut ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-12-17 19:27:27 -05:00
// storing the graph name for all diff entries:
2015-01-09 16:48:18 -05:00
FName GraphName = LhsGraph ? LhsGraph - > GetFName ( ) : RhsGraph - > GetFName ( ) ;
2014-12-17 19:27:27 -05:00
for ( auto & Entry : DiffsOut )
{
Entry . OwningGraph = GraphName ;
}
2014-03-14 14:13:41 -04:00
return bFoundDifferences ;
}
# undef LOCTEXT_NAMESPACE